diff --git a/.idea/modules.xml b/.idea/modules.xml index e9537356e97a..e177cad44135 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -36,6 +36,7 @@ + @@ -57,6 +58,7 @@ + diff --git a/RegExpSupport/src/org/intellij/lang/regexp/surroundWith/GroupSurrounder.java b/RegExpSupport/src/org/intellij/lang/regexp/surroundWith/GroupSurrounder.java index 0f4c0c886d49..3d01eb203184 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/surroundWith/GroupSurrounder.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/surroundWith/GroupSurrounder.java @@ -22,6 +22,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; @@ -84,6 +85,7 @@ class GroupSurrounder implements Surrounder { if (isInsideStringLiteral(e)) { final Document doc = editor.getDocument(); + PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(doc); final TextRange tr = e.getTextRange(); doc.replaceString(tr.getStartOffset(), tr.getEndOffset(), StringUtil.escapeStringCharacters(element.getText())); diff --git a/build/scripts/common_tests.gant b/build/scripts/common_tests.gant index c6eac41aceff..3c01e4e3e84b 100644 --- a/build/scripts/common_tests.gant +++ b/build/scripts/common_tests.gant @@ -8,6 +8,7 @@ target(compile: "Compile project") { loadProject() project["javac"] = "$jdk/bin/javac" project.targetFolder = out + ant.delete(dir: "$home/reports") project.clean() project.makeAll() } @@ -27,6 +28,7 @@ target('default': 'The default target') { pass("idea.test.group") pass("idea.test.patterns") pass("idea.fast.only") + pass("teamcity.build.tempDir") pass("teamcity.tests.recentlyFailedTests.file") jvmarg (value: "-Didea.platform.prefix=Idea") jvmarg (value: "-Didea.home.path=$home") diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index 403876d24d65..0ef5893a72fc 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -174,6 +174,9 @@ def layoutFull(String home, String targetDirectory) { layoutPlugin("maven") { + jar("maven-facade.jar") { + module("maven-facade") + } fileset(dir: "$home/plugins/maven/lib") } @@ -262,6 +265,15 @@ def layoutFull(String home, String targetDirectory) { fileset(dir: "${home}/plugins/groovy/lib") } } + + dir("Groovypp") { + dir("lib") { + jar("groovypp.jar") { + module("groovypp") + } + } + } + } } diff --git a/java/idea-ui/src/com/intellij/codeInsight/daemon/impl/AttachSourcesNotificationProvider.java b/java/idea-ui/src/com/intellij/codeInsight/daemon/impl/AttachSourcesNotificationProvider.java index 7f2ea324eaf8..6e67899786e3 100644 --- a/java/idea-ui/src/com/intellij/codeInsight/daemon/impl/AttachSourcesNotificationProvider.java +++ b/java/idea-ui/src/com/intellij/codeInsight/daemon/impl/AttachSourcesNotificationProvider.java @@ -24,31 +24,31 @@ import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; -import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; -import com.intellij.openapi.fileEditor.impl.EditorWindow; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.ui.configuration.PathUIUtils; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.ui.popup.ListSeparator; +import com.intellij.openapi.ui.popup.PopupStep; +import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.openapi.util.ActionCallback; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.psi.impl.compiled.ClsClassImpl; -import com.intellij.psi.impl.compiled.ClsFileImpl; -import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; import com.intellij.ui.EditorNotificationPanel; import com.intellij.ui.EditorNotifications; import com.intellij.ui.GuiUtils; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.Comparator; -import java.util.List; -import java.util.TreeSet; +import java.util.*; /** * @author Dmitry Avdeev @@ -80,8 +80,8 @@ public class AttachSourcesNotificationProvider implements EditorNotifications.Pr public EditorNotificationPanel createNotificationPanel(final VirtualFile file) { if (file.getFileType() != JavaClassFileType.INSTANCE) return null; - final Library library = findLibrary(file); - if (library == null) return null; + final List libraries = findOrderEntriesContainingFile(file); + if (libraries == null) return null; PsiFile psiFile = PsiManager.getInstance(myProject).findFile(file); final String fqn = JavaEditorFileSwapper.getFQN(psiFile); @@ -92,7 +92,7 @@ public class AttachSourcesNotificationProvider implements EditorNotifications.Pr final EditorNotificationPanel panel = new EditorNotificationPanel(); panel.setText(ProjectBundle.message("library.sources.not.found")); - final AttachSourcesProvider.AttachSourcesAction defaultAction = createDefaultAction(library, file); + final AttachSourcesProvider.AttachSourcesAction defaultAction = createDefaultAction(); TreeSet actions = new TreeSet( new Comparator() { @@ -106,13 +106,13 @@ public class AttachSourcesNotificationProvider implements EditorNotifications.Pr actions.add(defaultAction); for (AttachSourcesProvider each : Extensions.getExtensions(EXTENSION_POINT_NAME)) { - actions.addAll(each.getActions(library, psiFile)); + actions.addAll(each.getActions(libraries, psiFile)); } for (final AttachSourcesProvider.AttachSourcesAction each : actions) { panel.createActionLabel(GuiUtils.getTextWithoutMnemonicEscaping(each.getName()), new Runnable() { public void run() { - if (library != findLibrary(file)) { + if (!Comparing.equal(libraries, findOrderEntriesContainingFile(file))) { Messages.showErrorDialog(myProject, "Cannot find library for " + StringUtil.getShortName(fqn), "Error"); return; } @@ -128,7 +128,7 @@ public class AttachSourcesNotificationProvider implements EditorNotifications.Pr }); } }; - ActionCallback callback = each.perform(); + ActionCallback callback = each.perform(findOrderEntriesContainingFile(file)); callback.doWhenRejected(onFinish); callback.doWhenDone(onFinish); } @@ -138,7 +138,7 @@ public class AttachSourcesNotificationProvider implements EditorNotifications.Pr return panel; } - private AttachSourcesProvider.AttachSourcesAction createDefaultAction(final Library library, final VirtualFile file) { + private AttachSourcesProvider.AttachSourcesAction createDefaultAction() { return new AttachSourcesProvider.AttachSourcesAction() { public String getName() { return ProjectBundle.message("module.libraries.attach.sources.button"); @@ -148,41 +148,79 @@ public class AttachSourcesNotificationProvider implements EditorNotifications.Pr return ProjectBundle.message("library.attach.sources.action.busy.text"); } - public ActionCallback perform() { + public ActionCallback perform(final List libraries) { FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, true, false, true, true); descriptor.setTitle(ProjectBundle.message("library.attach.sources.action")); descriptor.setDescription(ProjectBundle.message("library.attach.sources.description")); - VirtualFile[] roots = library.getFiles(OrderRootType.CLASSES); + final Library firstLibrary = libraries.get(0).getLibrary(); + VirtualFile[] roots = firstLibrary != null ? firstLibrary.getFiles(OrderRootType.CLASSES) : VirtualFile.EMPTY_ARRAY; VirtualFile[] candidates = FileChooser.chooseFiles(myProject, descriptor, roots.length == 0 ? null : roots[0]); final VirtualFile[] files = PathUIUtils.scanAndSelectDetectedJavaSourceRoots(myProject, candidates); if (files.length == 0) { return new ActionCallback.Rejected(); } - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - final Library library = findLibrary(file); - assert library != null; - Library.ModifiableModel model = library.getModifiableModel(); - for (VirtualFile virtualFile : files) { - model.addRoot(virtualFile, OrderRootType.SOURCES); + if (libraries.size() == 1) { + appendSources(firstLibrary, files); + } else { + final List librariesToAppendSourcesTo = new ArrayList(libraries); + librariesToAppendSourcesTo.add(null); + JBPopupFactory.getInstance().createListPopup(new BaseListPopupStep("Multiple libraries contain file.
Choose libraries to attach sources to", librariesToAppendSourcesTo){ + @Override + public ListSeparator getSeparatorAbove(LibraryOrderEntry value) { + return value == null ? new ListSeparator() : null; } - model.commit(); - } - }); + + @NotNull + @Override + public String getTextFor(LibraryOrderEntry value) { + if (value != null) { + return value.getPresentableName() + " (" + value.getOwnerModule().getName() + ")"; + } + else { + return "All"; + } + } + + @Override + public PopupStep onChosen(LibraryOrderEntry libraryOrderEntry, boolean finalChoice) { + if (libraryOrderEntry != null) { + appendSources(libraryOrderEntry.getLibrary(), files); + } else { + for (LibraryOrderEntry libOrderEntry : libraries) { + appendSources(libOrderEntry.getLibrary(), files); + } + } + return FINAL_CHOICE; + } + }).showCenteredInCurrentWindow(myProject); + } return new ActionCallback.Done(); } }; } + private static void appendSources(final Library library, final VirtualFile[] files) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + Library.ModifiableModel model = library.getModifiableModel(); + for (VirtualFile virtualFile : files) { + model.addRoot(virtualFile, OrderRootType.SOURCES); + } + model.commit(); + } + }); + } + @Nullable - private Library findLibrary(VirtualFile file) { + private List findOrderEntriesContainingFile(VirtualFile file) { + final List libs = new ArrayList(); List entries = ProjectRootManager.getInstance(myProject).getFileIndex().getOrderEntriesForFile(file); for (OrderEntry entry : entries) { if (entry instanceof LibraryOrderEntry) { - return ((LibraryOrderEntry)entry).getLibrary(); + libs.add ((LibraryOrderEntry)entry); } } - return null; + return libs.isEmpty() ? null : libs; } } diff --git a/java/java-impl/src/com/intellij/application/options/BlankLinesSettingsProvider.java b/java/java-impl/src/com/intellij/application/options/BlankLinesSettingsProvider.java deleted file mode 100644 index e999a4ed8a0e..000000000000 --- a/java/java-impl/src/com/intellij/application/options/BlankLinesSettingsProvider.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2000-2009 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.application.options; - -import com.intellij.psi.codeStyle.CodeStyleSettingsProvider; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.application.ApplicationBundle; -import org.jetbrains.annotations.NotNull; - -/** - * @author yole - */ -public class BlankLinesSettingsProvider extends CodeStyleSettingsProvider { - @NotNull - public Configurable createSettingsPage(final CodeStyleSettings settings, final CodeStyleSettings originalSettings) { - return new CodeStyleBlankLinesConfigurable(settings, originalSettings); - } - - @Override - public String getConfigurableDisplayName() { - return ApplicationBundle.message("title.blank.lines"); - } -} diff --git a/java/java-impl/src/com/intellij/application/options/CodeStyleBlankLinesConfigurable.java b/java/java-impl/src/com/intellij/application/options/CodeStyleBlankLinesConfigurable.java deleted file mode 100644 index 21d8d9363308..000000000000 --- a/java/java-impl/src/com/intellij/application/options/CodeStyleBlankLinesConfigurable.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2000-2009 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.application.options; - -import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.psi.codeStyle.CodeStyleSettings; - -import javax.swing.*; - -public class CodeStyleBlankLinesConfigurable extends CodeStyleAbstractConfigurable { - public CodeStyleBlankLinesConfigurable(CodeStyleSettings settings, CodeStyleSettings cloneSettings) { - super(settings, cloneSettings, ApplicationBundle.message("title.blank.lines")); - } - - protected CodeStyleAbstractPanel createPanel(final CodeStyleSettings settings) { - return new CodeStyleBlankLinesPanel(settings); - } - - public Icon getIcon() { - return StdFileTypes.JAVA.getIcon(); - } - - public String getHelpTopic() { - return "reference.settingsdialog.IDE.globalcodestyle.blanklines"; - } -} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/application/options/CodeStyleBlankLinesPanel.java b/java/java-impl/src/com/intellij/application/options/CodeStyleBlankLinesPanel.java deleted file mode 100644 index 2b143d4b3443..000000000000 --- a/java/java-impl/src/com/intellij/application/options/CodeStyleBlankLinesPanel.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2000-2009 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.application.options; - -import com.intellij.ide.highlighter.JavaHighlighterFactory; -import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.openapi.editor.colors.EditorColorsScheme; -import com.intellij.openapi.editor.highlighter.EditorHighlighter; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.pom.java.LanguageLevel; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.psi.PsiFile; -import com.intellij.psi.util.PsiUtil; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.OptionGroup; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; - -public class CodeStyleBlankLinesPanel extends CodeStyleAbstractPanel { - private JTextField myKeepBlankLinesInDeclarations; - private JTextField myKeepBlankLinesInCode; - private JTextField myBlankLinesBeforePackage; - private JTextField myBlankLinesAfterPackage; - private JTextField myBlankLinesBeforeImports; - private JTextField myBlankLinesAfterImports; - private JTextField myBlankLinesAroundClass; - private JTextField myBlankLinesAroundField; - private JTextField myBlankLinesAroundMethod; - private JTextField myBlankLinesAroundFieldI; - private JTextField myBlankLinesAroundMethodI; - private JTextField myBlankLinesAfterClassHeader; - private JTextField myKeepBlankLinesBeforeRBrace; - - private final JPanel myPanel = new JPanel(new GridBagLayout()); - - public CodeStyleBlankLinesPanel(CodeStyleSettings settings) { - super(settings); - - myPanel - .add(createKeepBlankLinesPanel(), - new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 4, 0, 4), 0, 0)); - myPanel - .add(createBlankLinesPanel(), - new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 4, 0, 4), 0, 0)); - - final JPanel previewPanel = createPreviewPanel(); - myPanel - .add(previewPanel, - new GridBagConstraints(1, 0, 1, 2, 1, 1, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(0, 0, 0, 4), 0, 0)); - - installPreviewPanel(previewPanel); - addPanelToWatch(myPanel); - - } - - private JPanel createBlankLinesPanel() { - OptionGroup optionGroup = new OptionGroup(ApplicationBundle.message("title.blank.lines")); - - myBlankLinesBeforePackage = createTextField(); - optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.before.package.statement")), myBlankLinesBeforePackage); - - myBlankLinesAfterPackage = createTextField(); - optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.after.package.statement")), myBlankLinesAfterPackage); - - myBlankLinesBeforeImports = createTextField(); - optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.before.imports")), myBlankLinesBeforeImports); - - myBlankLinesAfterImports = createTextField(); - optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.after.imports")), myBlankLinesAfterImports); - - myBlankLinesAroundClass = createTextField(); - optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.around.class")), myBlankLinesAroundClass); - - myBlankLinesAroundField = createTextField(); - optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.around.field")), myBlankLinesAroundField); - - myBlankLinesAroundMethod = createTextField(); - optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.around.method")), myBlankLinesAroundMethod); - - myBlankLinesAroundFieldI = createTextField(); - optionGroup.add(new JLabel("Around field in interface:"), myBlankLinesAroundFieldI); - - myBlankLinesAroundMethodI = createTextField(); - optionGroup.add(new JLabel("Around method in interface:"), myBlankLinesAroundMethodI); - - myBlankLinesAfterClassHeader = createTextField(); - optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.after.class.header")), myBlankLinesAfterClassHeader); - - return optionGroup.createPanel(); - } - - private JPanel createKeepBlankLinesPanel() { - OptionGroup optionGroup = new OptionGroup(ApplicationBundle.message("title.keep.blank.lines")); - - myKeepBlankLinesInDeclarations = createTextField(); - optionGroup.add(new JLabel(ApplicationBundle.message("editbox.keep.blanklines.in.declarations")), myKeepBlankLinesInDeclarations); - - myKeepBlankLinesInCode = createTextField(); - optionGroup.add(new JLabel(ApplicationBundle.message("editbox.keep.blanklines.in.code")), myKeepBlankLinesInCode); - - myKeepBlankLinesBeforeRBrace = createTextField(); - optionGroup.add(new JLabel(ApplicationBundle.message("editbox.keep.blanklines.before.rbrace")), myKeepBlankLinesBeforeRBrace); - - return optionGroup.createPanel(); - } - - private static JPanel createPreviewPanel() { - JPanel panel = new JPanel(); - panel.setBorder(IdeBorderFactory.createTitledBorder(ApplicationBundle.message("title.preview"))); - panel.setPreferredSize(new Dimension(200, 0)); - return panel; - } - - protected EditorHighlighter createHighlighter(final EditorColorsScheme scheme) { - return JavaHighlighterFactory.createJavaHighlighter(scheme, LanguageLevel.HIGHEST); - } - - protected String getPreviewText() { - return "/*\n" + - " * This is a sample file.\n" + - " */\n" + - "package com.intellij.samples;\n" + - "import com.intellij.idea.Main;\n" + - "import javax.swing.*;\n" + - "import java.util.Vector;\n" + - "public class Foo {\n" + - " private int field1;\n" + - " private int field2;\n" + - " public void foo1() {\n\n" + - " }\n" + - " public void foo2() {\n" + - " }\n\n" + - "}"; - } - - protected void resetImpl(final CodeStyleSettings settings) { - myKeepBlankLinesInDeclarations.setText(String.valueOf(settings.KEEP_BLANK_LINES_IN_DECLARATIONS)); - myKeepBlankLinesInCode.setText(String.valueOf(settings.KEEP_BLANK_LINES_IN_CODE)); - myKeepBlankLinesBeforeRBrace.setText(String.valueOf(settings.KEEP_BLANK_LINES_BEFORE_RBRACE)); - myBlankLinesBeforePackage.setText(String.valueOf(settings.BLANK_LINES_BEFORE_PACKAGE)); - myBlankLinesAfterPackage.setText(String.valueOf(settings.BLANK_LINES_AFTER_PACKAGE)); - myBlankLinesBeforeImports.setText(String.valueOf(settings.BLANK_LINES_BEFORE_IMPORTS)); - myBlankLinesAfterImports.setText(String.valueOf(settings.BLANK_LINES_AFTER_IMPORTS)); - myBlankLinesAroundClass.setText(String.valueOf(settings.BLANK_LINES_AROUND_CLASS)); - myBlankLinesAroundField.setText(String.valueOf(settings.BLANK_LINES_AROUND_FIELD)); - myBlankLinesAroundMethod.setText(String.valueOf(settings.BLANK_LINES_AROUND_METHOD)); - myBlankLinesAroundFieldI.setText(String.valueOf(settings.BLANK_LINES_AROUND_FIELD_IN_INTERFACE)); - myBlankLinesAroundMethodI.setText(String.valueOf(settings.BLANK_LINES_AROUND_METHOD_IN_INTERFACE)); - myBlankLinesAfterClassHeader.setText(String.valueOf(settings.BLANK_LINES_AFTER_CLASS_HEADER)); - - } - - public void apply(CodeStyleSettings settings) { - settings.KEEP_BLANK_LINES_IN_DECLARATIONS = getValue(myKeepBlankLinesInDeclarations); - settings.KEEP_BLANK_LINES_IN_CODE = getValue(myKeepBlankLinesInCode); - settings.KEEP_BLANK_LINES_BEFORE_RBRACE = getValue(myKeepBlankLinesBeforeRBrace); - settings.BLANK_LINES_BEFORE_PACKAGE = getValue(myBlankLinesBeforePackage); - settings.BLANK_LINES_AFTER_PACKAGE = getValue(myBlankLinesAfterPackage); - settings.BLANK_LINES_BEFORE_IMPORTS = getValue(myBlankLinesBeforeImports); - settings.BLANK_LINES_AFTER_IMPORTS = getValue(myBlankLinesAfterImports); - settings.BLANK_LINES_AROUND_CLASS = getValue(myBlankLinesAroundClass); - settings.BLANK_LINES_AROUND_FIELD = getValue(myBlankLinesAroundField); - settings.BLANK_LINES_AROUND_METHOD = getValue(myBlankLinesAroundMethod); - - settings.BLANK_LINES_AROUND_FIELD_IN_INTERFACE = getValue(myBlankLinesAroundFieldI); - settings.BLANK_LINES_AROUND_METHOD_IN_INTERFACE = getValue(myBlankLinesAroundMethodI); - - settings.BLANK_LINES_AFTER_CLASS_HEADER = getValue(myBlankLinesAfterClassHeader); - - } - - public boolean isModified(CodeStyleSettings settings) { - boolean isModified; - isModified = settings.KEEP_BLANK_LINES_IN_DECLARATIONS != getValue(myKeepBlankLinesInDeclarations); - isModified |= settings.KEEP_BLANK_LINES_IN_CODE != getValue(myKeepBlankLinesInCode); - isModified |= settings.KEEP_BLANK_LINES_BEFORE_RBRACE != getValue(myKeepBlankLinesBeforeRBrace); - isModified |= settings.BLANK_LINES_BEFORE_PACKAGE != getValue(myBlankLinesBeforePackage); - isModified |= settings.BLANK_LINES_AFTER_PACKAGE != getValue(myBlankLinesAfterPackage); - isModified |= settings.BLANK_LINES_BEFORE_IMPORTS != getValue(myBlankLinesBeforeImports); - isModified |= settings.BLANK_LINES_AFTER_IMPORTS != getValue(myBlankLinesAfterImports); - isModified |= settings.BLANK_LINES_AROUND_CLASS != getValue(myBlankLinesAroundClass); - isModified |= settings.BLANK_LINES_AROUND_FIELD != getValue(myBlankLinesAroundField); - isModified |= settings.BLANK_LINES_AROUND_METHOD != getValue(myBlankLinesAroundMethod); - isModified |= settings.BLANK_LINES_AROUND_FIELD_IN_INTERFACE != getValue(myBlankLinesAroundFieldI); - isModified |= settings.BLANK_LINES_AROUND_METHOD_IN_INTERFACE != getValue(myBlankLinesAroundMethodI); - isModified |= settings.BLANK_LINES_AFTER_CLASS_HEADER != getValue(myBlankLinesAfterClassHeader); - return isModified; - - } - - private static int getValue(JTextField textField) { - int ret = 0; - try { - ret = Integer.parseInt(textField.getText()); - if (ret < 0) { - ret = 0; - } - if (ret > 10) { - ret = 10; - } - } - catch (NumberFormatException e) { - //bad number entered - } - return ret; - } - - private static JTextField createTextField() { - - return new JTextField(6); - } - - protected int getRightMargin() { - return 37; - } - - @NotNull - protected FileType getFileType() { - return StdFileTypes.JAVA; - } - - public JComponent getPanel() { - return myPanel; - } - - protected void prepareForReformat(final PsiFile psiFile) { - psiFile.putUserData(PsiUtil.FILE_LANGUAGE_LEVEL_KEY, LanguageLevel.HIGHEST); - } -} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/application/options/CodeStyleGenerationConfigurable.java b/java/java-impl/src/com/intellij/application/options/CodeStyleGenerationConfigurable.java index 33c1309bb02c..081345f1510e 100644 --- a/java/java-impl/src/com/intellij/application/options/CodeStyleGenerationConfigurable.java +++ b/java/java-impl/src/com/intellij/application/options/CodeStyleGenerationConfigurable.java @@ -27,8 +27,7 @@ import com.intellij.ui.ListUtil; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.Arrays; -import java.util.Comparator; +import java.util.*; public class CodeStyleGenerationConfigurable implements Configurable { JPanel myPanel; @@ -306,33 +305,116 @@ public class CodeStyleGenerationConfigurable implements Configurable { } private static class MembersOrderList extends JList { - private static final String FIELDS = ApplicationBundle.message("listbox.members.order.fields"); - private static final String METHODS = ApplicationBundle.message("listbox.members.order.methods"); - private static final String CONSTRUCTORS = ApplicationBundle.message("listbox.members.order.constructors"); - private static final String INNER_CLASSES = ApplicationBundle.message("listbox.members.order.inner.classes"); + + private static abstract class PropertyManager { + + public final String myName; + + protected PropertyManager(String nameKey) { + myName = ApplicationBundle.message(nameKey); + } + + abstract void apply(CodeStyleSettings settings, int value); + abstract int getValue(CodeStyleSettings settings); + } + + private static final Map PROPERTIES = new HashMap(); + static { + init(); + } private final DefaultListModel myModel; public MembersOrderList() { myModel = new DefaultListModel(); setModel(myModel); - setVisibleRowCount(4); + setVisibleRowCount(PROPERTIES.size()); } public void reset(final CodeStyleSettings settings) { myModel.removeAllElements(); - String[] strings = getStrings(settings); - for (String string : strings) { + for (String string : getPropertyNames(settings)) { myModel.addElement(string); } setSelectedIndex(0); } - private static String[] getStrings(final CodeStyleSettings settings) { - String[] strings = new String[]{FIELDS, METHODS, CONSTRUCTORS, INNER_CLASSES}; + private static void init() { + PropertyManager staticFieldManager = new PropertyManager("listbox.members.order.static.fields") { + @Override void apply(CodeStyleSettings settings, int value) { + settings.STATIC_FIELDS_ORDER_WEIGHT = value; + } + @Override int getValue(CodeStyleSettings settings) { + return settings.STATIC_FIELDS_ORDER_WEIGHT; + } + }; + PROPERTIES.put(staticFieldManager.myName, staticFieldManager); - Arrays.sort(strings, new Comparator() { + PropertyManager instanceFieldManager = new PropertyManager("listbox.members.order.fields") { + @Override void apply(CodeStyleSettings settings, int value) { + settings.FIELDS_ORDER_WEIGHT = value; + } + @Override int getValue(CodeStyleSettings settings) { + return settings.FIELDS_ORDER_WEIGHT; + } + }; + PROPERTIES.put(instanceFieldManager.myName, instanceFieldManager); + + PropertyManager constructorManager = new PropertyManager("listbox.members.order.constructors") { + @Override void apply(CodeStyleSettings settings, int value) { + settings.CONSTRUCTORS_ORDER_WEIGHT = value; + } + @Override int getValue(CodeStyleSettings settings) { + return settings.CONSTRUCTORS_ORDER_WEIGHT; + } + }; + PROPERTIES.put(constructorManager.myName, constructorManager); + + PropertyManager staticMethodManager = new PropertyManager("listbox.members.order.static.methods") { + @Override void apply(CodeStyleSettings settings, int value) { + settings.STATIC_METHODS_ORDER_WEIGHT = value; + } + @Override int getValue(CodeStyleSettings settings) { + return settings.STATIC_METHODS_ORDER_WEIGHT; + } + }; + PROPERTIES.put(staticMethodManager.myName, staticMethodManager); + + PropertyManager instanceMethodManager = new PropertyManager("listbox.members.order.methods") { + @Override void apply(CodeStyleSettings settings, int value) { + settings.METHODS_ORDER_WEIGHT = value; + } + @Override int getValue(CodeStyleSettings settings) { + return settings.METHODS_ORDER_WEIGHT; + } + }; + PROPERTIES.put(instanceMethodManager.myName, instanceMethodManager); + + PropertyManager staticInnerClassManager = new PropertyManager("listbox.members.order.inner.static.classes") { + @Override void apply(CodeStyleSettings settings, int value) { + settings.STATIC_INNER_CLASSES_ORDER_WEIGHT = value; + } + @Override int getValue(CodeStyleSettings settings) { + return settings.STATIC_INNER_CLASSES_ORDER_WEIGHT; + } + }; + PROPERTIES.put(staticInnerClassManager.myName, staticInnerClassManager); + + PropertyManager innerClassManager = new PropertyManager("listbox.members.order.inner.classes") { + @Override void apply(CodeStyleSettings settings, int value) { + settings.INNER_CLASSES_ORDER_WEIGHT = value; + } + @Override int getValue(CodeStyleSettings settings) { + return settings.INNER_CLASSES_ORDER_WEIGHT; + } + }; + PROPERTIES.put(innerClassManager.myName, innerClassManager); + } + + private static Iterable getPropertyNames(final CodeStyleSettings settings) { + List result = new ArrayList(PROPERTIES.keySet()); + Collections.sort(result, new Comparator() { public int compare(String o1, String o2) { int weight1 = getWeight(o1); int weight2 = getWeight(o2); @@ -340,57 +422,40 @@ public class CodeStyleGenerationConfigurable implements Configurable { } private int getWeight(String o) { - if (FIELDS.equals(o)) { - return settings.FIELDS_ORDER_WEIGHT; - } - else if (METHODS.equals(o)) { - return settings.METHODS_ORDER_WEIGHT; - } - else if (CONSTRUCTORS.equals(o)) { - return settings.CONSTRUCTORS_ORDER_WEIGHT; - } - else if (INNER_CLASSES.equals(o)) { - return settings.INNER_CLASSES_ORDER_WEIGHT; - } - else { + PropertyManager propertyManager = PROPERTIES.get(o); + if (propertyManager == null) { throw new IllegalArgumentException("unexpected " + o); } + return propertyManager.getValue(settings); } }); - return strings; + return result; } public void apply(CodeStyleSettings settings) { for (int i = 0; i < myModel.size(); i++) { Object o = myModel.getElementAt(i); - int weight = i + 1; - - if (FIELDS.equals(o)) { - settings.FIELDS_ORDER_WEIGHT = weight; - } - else if (METHODS.equals(o)) { - settings.METHODS_ORDER_WEIGHT = weight; - } - else if (CONSTRUCTORS.equals(o)) { - settings.CONSTRUCTORS_ORDER_WEIGHT = weight; - } - else if (INNER_CLASSES.equals(o)) { - settings.INNER_CLASSES_ORDER_WEIGHT = weight; - } - else { + if (o == null) { throw new IllegalArgumentException("unexpected " + o); } + PropertyManager propertyManager = PROPERTIES.get(o.toString()); + if (propertyManager == null) { + throw new IllegalArgumentException("unexpected " + o); + } + propertyManager.apply(settings, i + 1); } } public boolean isModified(CodeStyleSettings settings) { - String[] oldStrings = getStrings(settings); - String[] newStrings = new String[myModel.size()]; - for (int i = 0; i < newStrings.length; i++) { - newStrings[i] = (String)myModel.getElementAt(i); + Iterable oldProperties = getPropertyNames(settings); + int i = 0; + for (String property : oldProperties) { + if (i >= myModel.size() || !property.equals(myModel.getElementAt(i))) { + return true; + } + i++; } - - return !Arrays.equals(newStrings, oldStrings); + return false; } } } diff --git a/java/java-impl/src/com/intellij/application/options/CodeStyleSpacesConfigurable.java b/java/java-impl/src/com/intellij/application/options/CodeStyleSpacesConfigurable.java deleted file mode 100644 index dd820b14a4f3..000000000000 --- a/java/java-impl/src/com/intellij/application/options/CodeStyleSpacesConfigurable.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2000-2009 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.application.options; - -import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.psi.codeStyle.CodeStyleSettings; - -import javax.swing.*; - -public class CodeStyleSpacesConfigurable extends CodeStyleAbstractConfigurable { - public CodeStyleSpacesConfigurable(CodeStyleSettings settings, CodeStyleSettings cloneSettings) { - super(settings, cloneSettings, ApplicationBundle.message("title.spaces")); - } - - public Icon getIcon() { - return StdFileTypes.JAVA.getIcon(); - } - - protected CodeStyleAbstractPanel createPanel(final CodeStyleSettings settings) { - return new CodeStyleSpacesPanel(settings); - } - - public String getHelpTopic() { - return "reference.settingsdialog.IDE.globalcodestyle.spaces"; - } -} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/application/options/CodeStyleSpacesPanel.java b/java/java-impl/src/com/intellij/application/options/CodeStyleSpacesPanel.java deleted file mode 100644 index 51b8bffde30a..000000000000 --- a/java/java-impl/src/com/intellij/application/options/CodeStyleSpacesPanel.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2000-2009 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.application.options; - -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.EditorSettings; -import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.psi.codeStyle.CodeStyleSettings; - -import javax.swing.*; - -public class CodeStyleSpacesPanel extends OptionTreeWithPreviewPanel { - public CodeStyleSpacesPanel(CodeStyleSettings settings) { - super(settings); - } - - private static final String AROUND_OPERATORS = ApplicationBundle.message("group.spaces.around.operators"); - private static final String BEFORE_PARENTHESES = ApplicationBundle.message("group.spaces.before.parentheses"); - private static final String BEFORE_LEFT_BRACE = ApplicationBundle.message("group.spaces.before.left.brace"); - private static final String WITHIN_PARENTHESES = ApplicationBundle.message("group.spaces.within.parentheses"); - private static final String TERNARY_OPERATOR = ApplicationBundle.message("group.spaces.in.ternary.operator"); - private static final String OTHER = ApplicationBundle.message("group.spaces.other"); - - protected void initTables() { - initBooleanField("SPACE_BEFORE_METHOD_CALL_PARENTHESES", ApplicationBundle.message("checkbox.spaces.method.call.parentheses"), BEFORE_PARENTHESES); - initBooleanField("SPACE_BEFORE_METHOD_PARENTHESES", ApplicationBundle.message("checkbox.spaces.method.declaration.parentheses"), BEFORE_PARENTHESES); - initBooleanField("SPACE_BEFORE_IF_PARENTHESES", ApplicationBundle.message("checkbox.spaces.if.parentheses"), BEFORE_PARENTHESES); - initBooleanField("SPACE_BEFORE_WHILE_PARENTHESES", ApplicationBundle.message("checkbox.spaces.while.parentheses"), BEFORE_PARENTHESES); - initBooleanField("SPACE_BEFORE_FOR_PARENTHESES", ApplicationBundle.message("checkbox.spaces.for.parentheses"), BEFORE_PARENTHESES); - initBooleanField("SPACE_BEFORE_CATCH_PARENTHESES", ApplicationBundle.message("checkbox.spaces.catch.parentheses"), BEFORE_PARENTHESES); - initBooleanField("SPACE_BEFORE_SWITCH_PARENTHESES", ApplicationBundle.message("checkbox.spaces.switch.parentheses"), BEFORE_PARENTHESES); - initBooleanField("SPACE_BEFORE_SYNCHRONIZED_PARENTHESES", ApplicationBundle.message("checkbox.spaces.synchronized.parentheses"), BEFORE_PARENTHESES); - initBooleanField("SPACE_BEFORE_ANOTATION_PARAMETER_LIST", ApplicationBundle.message("checkbox.spaces.annotation.parameters"), BEFORE_PARENTHESES); - - initBooleanField("SPACE_AROUND_ASSIGNMENT_OPERATORS", ApplicationBundle.message("checkbox.spaces.assignment.operators"), AROUND_OPERATORS); - initBooleanField("SPACE_AROUND_LOGICAL_OPERATORS", ApplicationBundle.message("checkbox.spaces.logical.operators"), AROUND_OPERATORS); - initBooleanField("SPACE_AROUND_EQUALITY_OPERATORS", ApplicationBundle.message("checkbox.spaces.equality.operators"), AROUND_OPERATORS); - initBooleanField("SPACE_AROUND_RELATIONAL_OPERATORS", ApplicationBundle.message("checkbox.spaces.relational.operators"), AROUND_OPERATORS); - initBooleanField("SPACE_AROUND_BITWISE_OPERATORS", ApplicationBundle.message("checkbox.spaces.bitwise.operators"), AROUND_OPERATORS); - initBooleanField("SPACE_AROUND_ADDITIVE_OPERATORS", ApplicationBundle.message("checkbox.spaces.additive.operators"), AROUND_OPERATORS); - initBooleanField("SPACE_AROUND_MULTIPLICATIVE_OPERATORS", ApplicationBundle.message("checkbox.spaces.multiplicative.operators"), AROUND_OPERATORS); - initBooleanField("SPACE_AROUND_SHIFT_OPERATORS", ApplicationBundle.message("checkbox.spaces.shift.operators"), AROUND_OPERATORS); - - initBooleanField("SPACE_BEFORE_CLASS_LBRACE", ApplicationBundle.message("checkbox.spaces.class.left.brace"), BEFORE_LEFT_BRACE); - initBooleanField("SPACE_BEFORE_METHOD_LBRACE", ApplicationBundle.message("checkbox.spaces.method.left.brace"), BEFORE_LEFT_BRACE); - initBooleanField("SPACE_BEFORE_IF_LBRACE", ApplicationBundle.message("checkbox.spaces.if.left.brace"), BEFORE_LEFT_BRACE); - initBooleanField("SPACE_BEFORE_ELSE_LBRACE", ApplicationBundle.message("checkbox.spaces.else.left.brace"), BEFORE_LEFT_BRACE); - initBooleanField("SPACE_BEFORE_WHILE_LBRACE", ApplicationBundle.message("checkbox.spaces.while.left.brace"), BEFORE_LEFT_BRACE); - initBooleanField("SPACE_BEFORE_FOR_LBRACE", ApplicationBundle.message("checkbox.spaces.for.left.brace"), BEFORE_LEFT_BRACE); - initBooleanField("SPACE_BEFORE_DO_LBRACE", ApplicationBundle.message("checkbox.spaces.do.left.brace"), BEFORE_LEFT_BRACE); - initBooleanField("SPACE_BEFORE_SWITCH_LBRACE", ApplicationBundle.message("checkbox.spaces.switch.left.brace"), BEFORE_LEFT_BRACE); - initBooleanField("SPACE_BEFORE_TRY_LBRACE", ApplicationBundle.message("checkbox.spaces.try.left.brace"), BEFORE_LEFT_BRACE); - initBooleanField("SPACE_BEFORE_CATCH_LBRACE", ApplicationBundle.message("checkbox.spaces.catch.left.brace"), BEFORE_LEFT_BRACE); - initBooleanField("SPACE_BEFORE_FINALLY_LBRACE", ApplicationBundle.message("checkbox.spaces.finally.left.brace"), BEFORE_LEFT_BRACE); - initBooleanField("SPACE_BEFORE_SYNCHRONIZED_LBRACE", ApplicationBundle.message("checkbox.spaces.synchronized.left.brace"), BEFORE_LEFT_BRACE); - initBooleanField("SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE", ApplicationBundle.message("checkbox.spaces.array.initializer.left.brace"), BEFORE_LEFT_BRACE); - - initBooleanField("SPACE_WITHIN_PARENTHESES", ApplicationBundle.message("checkbox.spaces.parentheses"), WITHIN_PARENTHESES); - initBooleanField("SPACE_WITHIN_METHOD_CALL_PARENTHESES", ApplicationBundle.message("checkbox.spaces.checkbox.spaces.method.call.parentheses"), WITHIN_PARENTHESES); - initBooleanField("SPACE_WITHIN_METHOD_PARENTHESES", ApplicationBundle.message("checkbox.spaces.checkbox.spaces.method.declaration.parentheses"), WITHIN_PARENTHESES); - initBooleanField("SPACE_WITHIN_IF_PARENTHESES", ApplicationBundle.message("checkbox.spaces.if.parentheses"), WITHIN_PARENTHESES); - initBooleanField("SPACE_WITHIN_WHILE_PARENTHESES", ApplicationBundle.message("checkbox.spaces.while.parentheses"), WITHIN_PARENTHESES); - initBooleanField("SPACE_WITHIN_FOR_PARENTHESES", ApplicationBundle.message("checkbox.spaces.for.parentheses"), WITHIN_PARENTHESES); - initBooleanField("SPACE_WITHIN_CATCH_PARENTHESES", ApplicationBundle.message("checkbox.spaces.catch.parentheses"), WITHIN_PARENTHESES); - initBooleanField("SPACE_WITHIN_SWITCH_PARENTHESES", ApplicationBundle.message("checkbox.spaces.switch.parentheses"), WITHIN_PARENTHESES); - initBooleanField("SPACE_WITHIN_SYNCHRONIZED_PARENTHESES", ApplicationBundle.message("checkbox.spaces.synchronized.parentheses"), WITHIN_PARENTHESES); - initBooleanField("SPACE_WITHIN_CAST_PARENTHESES", ApplicationBundle.message("checkbox.spaces.type.cast.parentheses"), WITHIN_PARENTHESES); - initBooleanField("SPACE_WITHIN_ANNOTATION_PARENTHESES", ApplicationBundle.message("checkbox.spaces.annotation.parentheses"), WITHIN_PARENTHESES); - - initBooleanField("SPACE_BEFORE_QUEST", ApplicationBundle.message("checkbox.spaces.before.question"), TERNARY_OPERATOR); - initBooleanField("SPACE_AFTER_QUEST", ApplicationBundle.message("checkbox.spaces.after.question"), TERNARY_OPERATOR); - initBooleanField("SPACE_BEFORE_COLON", ApplicationBundle.message("checkbox.spaces.before.colon"), TERNARY_OPERATOR); - initBooleanField("SPACE_AFTER_COLON", ApplicationBundle.message("checkbox.spaces.after.colon"), TERNARY_OPERATOR); - - initBooleanField("SPACE_AFTER_LABEL", ApplicationBundle.message("checkbox.spaces.after.colon.in.label.declaration"), OTHER); - initBooleanField("SPACE_WITHIN_BRACKETS", ApplicationBundle.message("checkbox.spaces.within.brackets"), OTHER); - initBooleanField("SPACE_WITHIN_ARRAY_INITIALIZER_BRACES", ApplicationBundle.message("checkbox.spaces.within.array.initializer.braces"), OTHER); - initBooleanField("SPACE_AFTER_COMMA", ApplicationBundle.message("checkbox.spaces.after.comma"), OTHER); - initBooleanField("SPACE_BEFORE_COMMA", ApplicationBundle.message("checkbox.spaces.before.comma"), OTHER); - initBooleanField("SPACE_AFTER_SEMICOLON", ApplicationBundle.message("checkbox.spaces.after.semicolon"), OTHER); - initBooleanField("SPACE_BEFORE_SEMICOLON", ApplicationBundle.message("checkbox.spaces.before.semicolon"), OTHER); - initBooleanField("SPACE_AFTER_TYPE_CAST", ApplicationBundle.message("checkbox.spaces.after.type.cast"), OTHER); - } - - protected void setupEditorSettings(Editor editor) { - EditorSettings editorSettings = editor.getSettings(); - editorSettings.setWhitespacesShown(true); - editorSettings.setLineMarkerAreaShown(false); - editorSettings.setIndentGuidesShown(false); - editorSettings.setLineNumbersShown(false); - editorSettings.setFoldingOutlineShown(false); - editorSettings.setAdditionalColumnsCount(0); - editorSettings.setAdditionalLinesCount(1); - } - - protected String getPreviewText() { - return "@Annotation(param1=\"value1\", param2=\"value2\") public class Foo {\n" + - " int[] X = new int[]{1,3,5,6,7,87,1213,2};\n\n" + - " public void foo(int x, int y) {\n" + - " for(int i = 0; i < x; i++){\n" + - " y += (y ^ 0x123) << 2;\n" + - " }\n" + - " do {\n" + - " try {\n" + - " if(0 < x && x < 10) {\n" + - " while(x != y){\n" + - " x = f(x * 3 + 5);\n" + - " }\n" + - " } else {\n" + - " synchronized(this){\n" + - " switch(e.getCode()){\n" + - " //...\n" + - " }\n" + - " }\n" + - " }\n" + - " }\n" + - " catch(MyException e) {\n" + - " }\n" + - " finally {\n" + - " int[] arr = (int[])g(y);\n" + - " x = y >= 0 ? arr[y] : -1;\n" + - " }\n" + - " }while(true);\n" + - " }\n" + - "}"; - } - - public JComponent getPanel() { - return getInternalPanel(); - } -} diff --git a/java/java-impl/src/com/intellij/application/options/IndentAndBracesSettingsProvider.java b/java/java-impl/src/com/intellij/application/options/IndentAndBracesSettingsProvider.java deleted file mode 100644 index 6842b48427bb..000000000000 --- a/java/java-impl/src/com/intellij/application/options/IndentAndBracesSettingsProvider.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2000-2009 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.application.options; - -import com.intellij.psi.codeStyle.CodeStyleSettingsProvider; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.application.ApplicationBundle; -import org.jetbrains.annotations.NotNull; - -/** - * @author yole - */ -public class IndentAndBracesSettingsProvider extends CodeStyleSettingsProvider { - @NotNull - public Configurable createSettingsPage(final CodeStyleSettings settings, final CodeStyleSettings originalSettings) { - return new CodeStyleIndentAndBracesConfigurable(settings, originalSettings); - } - - @Override - public String getConfigurableDisplayName() { - return ApplicationBundle.message("title.alignment.and.braces"); - } -} diff --git a/java/java-impl/src/com/intellij/application/options/SpacesSettingsProvider.java b/java/java-impl/src/com/intellij/application/options/SpacesSettingsProvider.java deleted file mode 100644 index d6c97feb4c20..000000000000 --- a/java/java-impl/src/com/intellij/application/options/SpacesSettingsProvider.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2000-2009 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.application.options; - -import com.intellij.psi.codeStyle.CodeStyleSettingsProvider; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.application.ApplicationBundle; -import org.jetbrains.annotations.NotNull; - -/** - * @author yole - */ -public class SpacesSettingsProvider extends CodeStyleSettingsProvider { - @NotNull - public Configurable createSettingsPage(final CodeStyleSettings settings, final CodeStyleSettings originalSettings) { - return new CodeStyleSpacesConfigurable(settings, originalSettings); - } - - @Override - public String getConfigurableDisplayName() { - return ApplicationBundle.message("title.spaces"); - } -} diff --git a/java/java-impl/src/com/intellij/application/options/WrappingConfigurable.java b/java/java-impl/src/com/intellij/application/options/WrappingConfigurable.java deleted file mode 100644 index ca58f98690ce..000000000000 --- a/java/java-impl/src/com/intellij/application/options/WrappingConfigurable.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2000-2009 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.application.options; - -import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.psi.codeStyle.CodeStyleSettings; - -import javax.swing.*; - -public class WrappingConfigurable extends CodeStyleAbstractConfigurable { - public WrappingConfigurable(CodeStyleSettings settings, CodeStyleSettings cloneSettings) { - super(settings, cloneSettings, ApplicationBundle.message("title.wrapping")); - } - - public Icon getIcon() { - return StdFileTypes.JAVA.getIcon(); - } - - protected CodeStyleAbstractPanel createPanel(final CodeStyleSettings settings) { - return new WrappingPanel(settings); - } - - public String getHelpTopic() { - return "reference.settingsdialog.IDE.globalcodestyle.wrap"; - } -} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/application/options/WrappingPanel.java b/java/java-impl/src/com/intellij/application/options/WrappingPanel.java deleted file mode 100644 index 2d3796fe8a1d..000000000000 --- a/java/java-impl/src/com/intellij/application/options/WrappingPanel.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2000-2009 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.application.options; - -import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.psi.codeStyle.CodeStyleSettings; - -/** - * @author max - */ -public class WrappingPanel extends OptionTableWithPreviewPanel { - private static final String METHOD_PARAMETERS_WRAPPING = ApplicationBundle.message("combobox.wrap.method.declaration.parameters"); - private static final String CALL_PARAMETERS_WRAPPING = ApplicationBundle.message("combobox.wrap.method.call.arguments"); - private static final String CALL_CHAIN_WRAPPING = ApplicationBundle.message("combobox.wrap.chained.method.calls"); - private static final String FOR_STATEMENT_WRAPPING = ApplicationBundle.message("combobox.wrap.for.statement"); - private static final String BINARY_OPERATION_WRAPPING = ApplicationBundle.message("combobox.wrap.binary.operations"); - private static final String[] FULL_WRAP_OPTIONS = new String[] { - ApplicationBundle.message("combobox.codestyle.do.not.wrap"), - ApplicationBundle.message("combobox.codestyle.wrap.if.long"), - ApplicationBundle.message("combobox.codestyle.chop.down.if.long"), - ApplicationBundle.message("combobox.codestyle.wrap.always") - }; - private static final String[] SINGLE_ITEM_WRAP_OPTIONS = new String[]{ - ApplicationBundle.message("combobox.codestyle.do.not.wrap"), - ApplicationBundle.message("combobox.codestyle.wrap.if.long"), - ApplicationBundle.message("combobox.codestyle.wrap.always") - }; - private static final int[] FULL_WRAP_VALUES = new int[]{CodeStyleSettings.DO_NOT_WRAP, - CodeStyleSettings.WRAP_AS_NEEDED, - CodeStyleSettings.WRAP_AS_NEEDED | - CodeStyleSettings.WRAP_ON_EVERY_ITEM, - CodeStyleSettings.WRAP_ALWAYS}; - private static final int[] SINGLE_ITEM_WRAP_VALUES = new int[]{CodeStyleSettings.DO_NOT_WRAP, - CodeStyleSettings.WRAP_AS_NEEDED, - CodeStyleSettings.WRAP_ALWAYS}; - private static final String EXTENDS_LIST_WRAPPING = ApplicationBundle.message("combobox.wrap.extends.implements.list"); - private static final String EXTENDS_KEYWORD_WRAPPING = ApplicationBundle.message("combobox.wrap.extends.implements.keyword"); - private static final String THROWS_LIST_WRAPPING = ApplicationBundle.message("combobox.wrap.throws.list"); - private static final String THROWS_KEYWORD_WRAPPING = ApplicationBundle.message("combobox.wrap.throws.keyword"); - private static final String PARENTHESIZED_EXPRESSION = ApplicationBundle.message("combobox.wrap.parenthesized.expression"); - private static final String TERNARY_OPERATION_WRAPPING = ApplicationBundle.message("combobox.wrap.ternary.operation"); - private static final String ASSIGNMENT_WRAPPING = ApplicationBundle.message("combobox.wrap.assignment.statement"); - private static final String ARRAY_INITIALIZER_WRAPPING = ApplicationBundle.message("combobox.wrap.array.initializer"); - private static final String LABELED_STATEMENT_WRAPPING = ApplicationBundle.message("combobox.wrap.label.declaration"); - private static final String MODIFIER_LIST_WRAPPING = ApplicationBundle.message("combobox.wrap.modifier.list"); - private static final String ASSERT_STATEMENT_WRAPPING = ApplicationBundle.message("combobox.wrap.assert.statement"); - - public WrappingPanel(CodeStyleSettings settings) { - super(settings); - } - - protected void initTables() { - initRadioGroupField("EXTENDS_LIST_WRAP", EXTENDS_LIST_WRAPPING, FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initRadioGroupField("EXTENDS_KEYWORD_WRAP", EXTENDS_KEYWORD_WRAPPING, SINGLE_ITEM_WRAP_OPTIONS, - SINGLE_ITEM_WRAP_VALUES); - - initRadioGroupField("METHOD_PARAMETERS_WRAP", METHOD_PARAMETERS_WRAPPING, FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initBooleanField("METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE", ApplicationBundle.message("checkbox.wrap.new.line.after.lpar"), METHOD_PARAMETERS_WRAPPING); - initBooleanField("METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE", ApplicationBundle.message("checkbox.wrap.place.rpar.on.new.line"), METHOD_PARAMETERS_WRAPPING); - - initRadioGroupField("THROWS_LIST_WRAP", THROWS_LIST_WRAPPING, FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initRadioGroupField("THROWS_KEYWORD_WRAP", THROWS_KEYWORD_WRAPPING, SINGLE_ITEM_WRAP_OPTIONS, - SINGLE_ITEM_WRAP_VALUES); - - initRadioGroupField("CALL_PARAMETERS_WRAP", CALL_PARAMETERS_WRAPPING, FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initBooleanField("PREFER_PARAMETERS_WRAP", ApplicationBundle.message("checkbox.wrap.take.priority.over.call.chain.wrapping"), CALL_PARAMETERS_WRAPPING); - initBooleanField("CALL_PARAMETERS_LPAREN_ON_NEXT_LINE", ApplicationBundle.message("checkbox.wrap.new.line.after.lpar"), CALL_PARAMETERS_WRAPPING); - initBooleanField("CALL_PARAMETERS_RPAREN_ON_NEXT_LINE", ApplicationBundle.message("checkbox.wrap.place.rpar.on.new.line"), CALL_PARAMETERS_WRAPPING); - - initRadioGroupField("METHOD_CALL_CHAIN_WRAP", CALL_CHAIN_WRAPPING, FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - - initRadioGroupField("FOR_STATEMENT_WRAP", FOR_STATEMENT_WRAPPING, FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initBooleanField("FOR_STATEMENT_LPAREN_ON_NEXT_LINE", ApplicationBundle.message("checkbox.wrap.new.line.after.lpar"), FOR_STATEMENT_WRAPPING); - initBooleanField("FOR_STATEMENT_RPAREN_ON_NEXT_LINE", ApplicationBundle.message("checkbox.wrap.place.rpar.on.new.line"), FOR_STATEMENT_WRAPPING); - - initRadioGroupField("BINARY_OPERATION_WRAP", BINARY_OPERATION_WRAPPING, FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initBooleanField("BINARY_OPERATION_SIGN_ON_NEXT_LINE", ApplicationBundle.message("checkbox.wrap.operation.sign.on.next.line"), BINARY_OPERATION_WRAPPING); - - initRadioGroupField("ASSIGNMENT_WRAP", ASSIGNMENT_WRAPPING, FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initBooleanField("PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE", ApplicationBundle.message("checkbox.wrap.assignment.sign.on.next.line"), ASSIGNMENT_WRAPPING); - - initRadioGroupField("TERNARY_OPERATION_WRAP", TERNARY_OPERATION_WRAPPING, FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initBooleanField("TERNARY_OPERATION_SIGNS_ON_NEXT_LINE", ApplicationBundle.message("checkbox.wrap.quest.and.colon.signs.on.next.line"), - TERNARY_OPERATION_WRAPPING); - - initBooleanField("PARENTHESES_EXPRESSION_LPAREN_WRAP", ApplicationBundle.message("checkbox.wrap.new.line.after.lpar"), PARENTHESIZED_EXPRESSION); - initBooleanField("PARENTHESES_EXPRESSION_RPAREN_WRAP", ApplicationBundle.message("checkbox.wrap.place.rpar.on.new.line"), PARENTHESIZED_EXPRESSION); - - initRadioGroupField("ARRAY_INITIALIZER_WRAP", ARRAY_INITIALIZER_WRAPPING, FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initBooleanField("ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE", ApplicationBundle.message("checkbox.wrap.new.line.after.lbrace"), ARRAY_INITIALIZER_WRAPPING); - initBooleanField("ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE", ApplicationBundle.message("checkbox.wrap.place.rbrace.on.new.line"), ARRAY_INITIALIZER_WRAPPING); - - initRadioGroupField("LABELED_STATEMENT_WRAP", LABELED_STATEMENT_WRAPPING, SINGLE_ITEM_WRAP_OPTIONS, SINGLE_ITEM_WRAP_VALUES); - - initBooleanField("MODIFIER_LIST_WRAP", ApplicationBundle.message("checkbox.wrap.after.modifier.list"), MODIFIER_LIST_WRAPPING); - - initRadioGroupField("ASSERT_STATEMENT_WRAP", ASSERT_STATEMENT_WRAPPING, FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initBooleanField("ASSERT_STATEMENT_COLON_ON_NEXT_LINE", ApplicationBundle.message("checkbox.wrap.colon.signs.on.next.line"), ASSERT_STATEMENT_WRAPPING); - - initRadioGroupField("CLASS_ANNOTATION_WRAP", ApplicationBundle.message("checkbox.wrap.classes.annotation"), FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initRadioGroupField("METHOD_ANNOTATION_WRAP", ApplicationBundle.message("checkbox.wrap.methods.annotation"), FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initRadioGroupField("FIELD_ANNOTATION_WRAP", ApplicationBundle.message("checkbox.wrap.fields.annotation"), FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initRadioGroupField("PARAMETER_ANNOTATION_WRAP", ApplicationBundle.message("checkbox.wrap.parameters.annotation"), FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initRadioGroupField("VARIABLE_ANNOTATION_WRAP", ApplicationBundle.message("checkbox.wrap.local.variables.annotation"), FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - initRadioGroupField("ENUM_CONSTANTS_WRAP", ApplicationBundle.message("checkbox.wrap.enum.constants"), FULL_WRAP_OPTIONS, FULL_WRAP_VALUES); - - } - - protected int getRightMargin() { - return 37; - } - - protected String getPreviewText() { //| Margin is here - return "/*\n" + - " * This is a sample file.\n" + - " */\n" + - "\n" + - "public class ThisIsASampleClass extends C1 implements I1, I2, I3, I4, I5 {\n" + - " private int f1;\n" + - " private int f2;\n" + - " public void foo1(int i1, int i2, int i3, int i4, int i5, int i6, int i7) {}\n" + - " public static void longerMethod() throws Exception1, Exception2, Exception3 {\n" + - " int[] a = new int[] {1, 2, 0x0052, 0x0053, 0x0054};\n" + - " foo1(0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057);\n" + - " int x = (3 + 4 + 5 + 6) * (7 + 8 + 9 + 10) * (11 + 12 + 13 + 14 + 0xFFFFFFFF);\n" + - " String s1, s2, s3;\n" + - " s1 = s2 = s3 = \"012345678901456\";\n" + - " assert i + j + k + l + n+ m <= 2 : \"assert description\";" + - " int y = 2 > 3 ? 7 + 8 + 9 : 11 + 12 + 13;\n" + - " label: " + - " for (int i = 0; i < 0xFFFFFF; i += 2) {\n" + - " super.getFoo().foo().getBar().bar();\n" + - " }\n" + - " }\n" + - "}\n" + - "\n" + - "enum Breed {\n" + - " Dalmatian(), Labrador(), Dachshund()\n" + - "}\n" + - "\n" + - "@Annotation1 @Annotation2 @Annotation3(param1=\"value1\", param2=\"value2\") @Annotation4 class Foo {\n" + - " @Annotation1 @Annotation3(param1=\"value1\", param2=\"value2\") public static void foo(){\n" + - " }\n" + - " @Annotation1 @Annotation3(param1=\"value1\", param2=\"value2\") public static int myFoo;\n" + - " public void method(@Annotation1 @Annotation3(param1=\"value1\", param2=\"value2\") final int param){\n" + - " @Annotation1 @Annotation3(param1=\"value1\", param2=\"value2\") final int localVariable;" + - " }\n" + - "}"; - } -} diff --git a/java/java-impl/src/com/intellij/application/options/WrappingSettingsProvider.java b/java/java-impl/src/com/intellij/application/options/WrappingSettingsProvider.java deleted file mode 100644 index 08016e7bbb87..000000000000 --- a/java/java-impl/src/com/intellij/application/options/WrappingSettingsProvider.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2000-2009 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.application.options; - -import com.intellij.psi.codeStyle.CodeStyleSettingsProvider; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.application.ApplicationBundle; -import org.jetbrains.annotations.NotNull; - -/** - * @author yole - */ -public class WrappingSettingsProvider extends CodeStyleSettingsProvider { - @NotNull - public Configurable createSettingsPage(final CodeStyleSettings settings, final CodeStyleSettings originalSettings) { - return new WrappingConfigurable(settings, originalSettings); - } - - @Override - public String getConfigurableDisplayName() { - return ApplicationBundle.message("title.wrapping"); - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java index baec1e02f339..e1d7f102d660 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java @@ -43,6 +43,7 @@ import com.intellij.psi.impl.source.jsp.jspJava.JspClass; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.*; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -747,6 +748,7 @@ public class HighlightClassUtil { return place == aClass; } + @Nullable public static HighlightInfo checkCreateInnerClassFromStaticContext(PsiNewExpression expression) { PsiType type = expression.getType(); if (type == null || type instanceof PsiArrayType || type instanceof PsiPrimitiveType) return null; @@ -791,19 +793,18 @@ public class HighlightClassUtil { return null; } + @Nullable public static HighlightInfo reportIllegalEnclosingUsage(PsiElement place, PsiClass aClass, PsiClass outerClass, PsiElement elementToHighlight) { - if (outerClass != null && !PsiTreeUtil.isAncestor(outerClass, place, false)) { + if (outerClass != null && !PsiTreeUtil.isContextAncestor(outerClass, place, false)) { String description = JavaErrorMessages.message("is.not.an.enclosing.class", HighlightUtil.formatClass(outerClass)); return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, elementToHighlight, description); } PsiModifierListOwner staticParent = PsiUtil.getEnclosingStaticElement(place, outerClass); if (staticParent != null) { String description = JavaErrorMessages.message("cannot.be.referenced.from.static.context", - outerClass == null - ? "" - : HighlightUtil.formatClass(outerClass) + "." + PsiKeyword.THIS); + outerClass == null ? "" : HighlightUtil.formatClass(outerClass) + "." + PsiKeyword.THIS); HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, elementToHighlight, description); // make context not static or referenced class static IntentionAction fix = QUICK_FIX_FACTORY.createModifierListFix(staticParent, PsiModifier.STATIC, false, false); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java index bc3a15c092e4..b418627e735e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java @@ -59,7 +59,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { protected boolean isAvailableImpl(int offset) { final PsiMethodCallExpression call = getMethodCall(); - if (call == null) return false; + if (call == null || !call.isValid()) return false; PsiReferenceExpression ref = call.getMethodExpression(); String name = ref.getReferenceName(); @@ -90,8 +90,8 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { PsiExpressionList argumentList = call.getArgumentList(); List errorsInArgList = DaemonCodeAnalyzerImpl.getHighlights(document, HighlightSeverity.ERROR, project, - //strictly inside arg list - argumentList.getTextRange().getStartOffset()+1, + //strictly inside arg list + argumentList.getTextRange().getStartOffset()+1, argumentList.getTextRange().getEndOffset()-1); return !errorsInArgList.isEmpty(); } @@ -117,7 +117,6 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { } protected void invokeImpl(final PsiClass targetClass) { - if (targetClass == null) return; PsiMethodCallExpression expression = getMethodCall(); if (expression == null) return; @@ -170,6 +169,9 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { setupVisibility(parentClass, targetClass, method.getModifierList()); + expression = getMethodCall(); + LOG.assertTrue(expression.isValid()); + if (shouldCreateStaticMember(expression.getMethodExpression(), targetClass) && !shouldBeAbstract(targetClass)) { PsiUtil.setModifierProperty(method, PsiModifier.STATIC, true); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateParameterFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateParameterFromUsageFix.java index 139392a6c745..ba800493e94b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateParameterFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateParameterFromUsageFix.java @@ -82,7 +82,11 @@ public class CreateParameterFromUsageFix extends CreateVarFromUsageFix { List parameterInfos = new ArrayList(Arrays.asList(ParameterInfoImpl.fromMethod(method))); ParameterInfoImpl parameterInfo = new ParameterInfoImpl(-1, varName, type, PsiTypesUtil.getDefaultValueOfType(type), false); - parameterInfos.add(parameterInfo); + if (!method.isVarArgs()) { + parameterInfos.add(parameterInfo); + } else { + parameterInfos.add(parameterInfos.size() - 1, parameterInfo); + } if (ApplicationManager.getApplication().isUnitTestMode()) { ParameterInfoImpl[] array = parameterInfos.toArray(new ParameterInfoImpl[parameterInfos.size()]); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java index 15216e0a4ccf..31cc586b359a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java @@ -27,6 +27,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.PopupChooserBuilder; +import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; @@ -46,6 +47,7 @@ public class StaticImportMethodFix implements IntentionAction { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.StaticImportMethodFix"); private final SmartPsiElementPointer myMethodCall; private List candidates; + private static final int OPTIONS = PsiFormatUtil.SHOW_NAME; public StaticImportMethodFix(@NotNull PsiMethodCallExpression methodCallExpression) { myMethodCall = SmartPointerManager.getInstance(methodCallExpression.getProject()).createSmartPsiElementPointer(methodCallExpression); @@ -55,8 +57,7 @@ public class StaticImportMethodFix implements IntentionAction { public String getText() { String text = QuickFixBundle.message("static.import.method.text"); if (candidates.size() == 1) { - final int options = PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_CONTAINING_CLASS | PsiFormatUtil.SHOW_FQ_NAME; - text += " '" + PsiFormatUtil.formatMethod(candidates.get(0), PsiSubstitutor.EMPTY, options, 0)+"'"; + text += " '" + PsiFormatUtil.formatMethod(candidates.get(0), PsiSubstitutor.EMPTY, OPTIONS, 0)+"'"; } else { text += "..."; @@ -110,6 +111,20 @@ public class StaticImportMethodFix implements IntentionAction { } } List result = applicableList.isEmpty() ? list : applicableList; + for (int i = result.size() - 1; i >= 0; i--) { + PsiMethod method = result.get(i); + PsiClass containingClass = method.getContainingClass(); + for (int j = i+1; j(candidates)); - list.setCellRenderer(new MethodCellRenderer(true)); + list.setCellRenderer(new MethodCellRenderer(true, OPTIONS)); new PopupChooserBuilder(list). setTitle(QuickFixBundle.message("static.import.method.choose.method.to.import")). setMovable(true). diff --git a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java index a2455da108b2..54f184930b18 100644 --- a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java +++ b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java @@ -592,16 +592,7 @@ public class JavaFoldingBuilder extends FoldingBuilderEx implements DumbAware { if (!baseClass.hasModifierProperty(PsiModifier.ABSTRACT)) return false; - final PsiMethod[] constructors = baseClass.getConstructors(); - boolean hasEmptyConstructor = constructors.length == 0; - for (final PsiMethod method : constructors) { - if (method.getParameterList().getParametersCount() == 0) { - hasEmptyConstructor = true; - break; - } - } - - if (!hasEmptyConstructor) return false; + if (!PsiUtil.hasDefaultConstructor(baseClass, true)) return false; for (final PsiMethod method : baseClass.getMethods()) { if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { diff --git a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java index 9bf82b401d38..895c921d2978 100644 --- a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java @@ -75,7 +75,8 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool { docComment.accept(getVisitor(references, docCommentOwner, problems, manager, isOnTheFly)); for (PsiJavaCodeReferenceElement reference : references) { final List classesToImport = new ImportClassFix(reference).getClassesToImport(); - problems.add(manager.createProblemDescriptor(reference, cannotResolveSymbolMessage("" + reference.getText() + ""), + final PsiElement referenceNameElement = reference.getReferenceNameElement(); + problems.add(manager.createProblemDescriptor(referenceNameElement != null ? referenceNameElement : reference, cannotResolveSymbolMessage("" + reference.getText() + ""), !isOnTheFly || classesToImport.isEmpty() ? null : new AddImportFix(classesToImport), ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, isOnTheFly)); } @@ -180,9 +181,9 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool { } fixes.add(new RemoveTagFix(tagName, paramName, tag)); - problems.add(inspectionManager.createProblemDescriptor(valueElement, cannotResolveSymbolMessage(params), onTheFly, - fixes.toArray(new LocalQuickFix[fixes.size()]), - ProblemHighlightType.LIKE_UNKNOWN_SYMBOL)); + problems.add(inspectionManager.createProblemDescriptor(valueElement, reference.getRangeInElement(), cannotResolveSymbolMessage(params), + ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, onTheFly, + fixes.toArray(new LocalQuickFix[fixes.size()]))); } } } @@ -231,7 +232,7 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool { } public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { - final PsiElement element = descriptor.getPsiElement(); + final PsiElement element = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiJavaCodeReferenceElement.class); if (element instanceof PsiJavaCodeReferenceElement) { final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)element; Collections.sort(myClassesToImport, new PsiProximityComparator(referenceElement.getElement())); diff --git a/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java b/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java index 41613969c997..f28ab0552830 100644 --- a/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java +++ b/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java @@ -634,8 +634,7 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{ public static boolean addResult(Processor results, PsiReference ref, FindUsagesOptions options, PsiElement refElement) { if (filterUsage(ref.getElement(), options, refElement)){ TextRange rangeInElement = ref.getRangeInElement(); - final boolean validRef = ref.isReferenceTo(refElement); - return results.process(new UsageInfo(ref.getElement(), rangeInElement.getStartOffset(), rangeInElement.getEndOffset(), !validRef)); + return results.process(new UsageInfo(ref.getElement(), rangeInElement.getStartOffset(), rangeInElement.getEndOffset(), false)); } return true; } diff --git a/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaFileTreeModel.java b/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaFileTreeModel.java index 6c13f66d3afb..8e66a3e81f86 100644 --- a/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaFileTreeModel.java +++ b/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaFileTreeModel.java @@ -15,6 +15,7 @@ */ package com.intellij.ide.structureView.impl.java; +import com.intellij.ide.structureView.StructureViewModel; import com.intellij.ide.structureView.StructureViewTreeElement; import com.intellij.ide.structureView.TextEditorBasedStructureViewModel; import com.intellij.ide.util.treeView.smartTree.Filter; @@ -23,7 +24,7 @@ import com.intellij.ide.util.treeView.smartTree.Sorter; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; -public class JavaFileTreeModel extends TextEditorBasedStructureViewModel { +public class JavaFileTreeModel extends TextEditorBasedStructureViewModel implements StructureViewModel.ElementInfoProvider { private final PsiJavaFile myFile; public JavaFileTreeModel(@NotNull PsiJavaFile file) { @@ -61,6 +62,16 @@ public class JavaFileTreeModel extends TextEditorBasedStructureViewModel { return myFile; } + public boolean isAlwaysShowsPlus(StructureViewTreeElement element) { + Object value = element.getValue(); + return value instanceof PsiClass || value instanceof PsiFile; + } + + public boolean isAlwaysLeaf(StructureViewTreeElement element) { + Object value = element.getValue(); + return value instanceof PsiMethod || value instanceof PsiField; + } + @Override protected boolean isSuitable(final PsiElement element) { if (super.isSuitable(element)) { diff --git a/java/java-impl/src/com/intellij/ide/util/MethodCellRenderer.java b/java/java-impl/src/com/intellij/ide/util/MethodCellRenderer.java index cef9714066d0..ad9f5ffda70e 100644 --- a/java/java-impl/src/com/intellij/ide/util/MethodCellRenderer.java +++ b/java/java-impl/src/com/intellij/ide/util/MethodCellRenderer.java @@ -23,16 +23,21 @@ import javax.swing.*; public class MethodCellRenderer extends PsiElementListCellRenderer{ private final boolean myShowMethodNames; private final PsiClassListCellRenderer myClassListCellRenderer = new PsiClassListCellRenderer(); + private final int myOptions; + public MethodCellRenderer(boolean showMethodNames) { + this(showMethodNames, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS); + } + public MethodCellRenderer(boolean showMethodNames, int options) { myShowMethodNames = showMethodNames; + myOptions = options; } public String getElementText(PsiMethod element) { final PsiNamedElement container = fetchContainer(element); String text = container instanceof PsiClass ? myClassListCellRenderer.getElementText((PsiClass)container) : container.getName(); if (myShowMethodNames) { - final int options = PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS; - text += "."+PsiFormatUtil.formatMethod(element, PsiSubstitutor.EMPTY, options, PsiFormatUtil.SHOW_TYPE); + text += "."+PsiFormatUtil.formatMethod(element, PsiSubstitutor.EMPTY, myOptions, PsiFormatUtil.SHOW_TYPE); } return text; } @@ -43,16 +48,11 @@ public class MethodCellRenderer extends PsiElementListCellRenderer{ private static PsiNamedElement fetchContainer(PsiMethod element){ PsiClass aClass = element.getContainingClass(); - if (aClass == null) { - return element.getContainingFile(); - } - else { - return aClass; - } + return aClass == null ? element.getContainingFile() : aClass; } public String getContainerText(final PsiMethod element, final String name) { - return myClassListCellRenderer.getContainerTextStatic(element); + return PsiClassListCellRenderer.getContainerTextStatic(element); } public int getIconFlags() { diff --git a/java/java-impl/src/com/intellij/openapi/options/colors/pages/JavaColorSettingsPage.java b/java/java-impl/src/com/intellij/openapi/options/colors/pages/JavaColorSettingsPage.java index f8a0f0b917dc..25f2a3e6f3f9 100644 --- a/java/java-impl/src/com/intellij/openapi/options/colors/pages/JavaColorSettingsPage.java +++ b/java/java-impl/src/com/intellij/openapi/options/colors/pages/JavaColorSettingsPage.java @@ -82,10 +82,7 @@ public class JavaColorSettingsPage implements ColorSettingsPage, InspectionColor new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.annotation.attribute.name"), CodeInsightColors.ANNOTATION_ATTRIBUTE_NAME_ATTRIBUTES) }; - private static final ColorDescriptor[] ourColorDescriptors = new ColorDescriptor[]{ - new ColorDescriptor(OptionsBundle.message("options.java.color.descriptor.method.separator.color"), CodeInsightColors.METHOD_SEPARATORS_COLOR, ColorDescriptor.Kind.FOREGROUND) - - }; + private static final ColorDescriptor[] ourColorDescriptors = new ColorDescriptor[0]; @NonNls private static final Map ourTags = new HashMap(); static { diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index af72d015c04a..d1044df5f0a2 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -730,7 +730,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo if (role == ChildRole.CLASS_OR_INTERFACE_KEYWORD) return defaultAlignment; if (myIsAfterClassKeyword) return null; if (role == ChildRole.MODIFIER_LIST) return defaultAlignment; - if (role == ChildRole.DOC_COMMENT) return defaultAlignment; return null; } diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java index 5726856ca120..0ba345de6c88 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java @@ -249,6 +249,9 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { myResult = Spacing.createSpacing(0, mySettings.SPACE_BEFORE_CLASS_LBRACE ? 1 : 0, 0, true, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE, lines); } + else if (myRole1 == ChildRole.CLASS) { + setAroundClassSpacing(); + } else { final int blankLines = getLinesAroundMethod() + 1; myResult = Spacing @@ -262,6 +265,9 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { 0, Integer.MAX_VALUE, minLineFeeds, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE ); } + else if (myRole2 == ChildRole.CLASS) { + setAroundClassSpacing(); + } else { final int blankLines = getLinesAroundMethod() + 1; myResult = Spacing @@ -359,6 +365,15 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { } } + /** + * Initializes {@link #myResult} property with {@link Spacing} which 'min line feeds' property is defined + * from {@link CodeStyleSettings#BLANK_LINES_AROUND_CLASS} value. + */ + private void setAroundClassSpacing() { + myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, mySettings.BLANK_LINES_AROUND_CLASS + 1, + mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS); + } + private boolean processMethod() { if (myRole2 == ChildRole.METHOD || myChild2.getElementType() == JavaElementType.METHOD) { if (myRole1 == ChildRole.LBRACE) { diff --git a/java/java-impl/src/com/intellij/psi/impl/light/LightClass.java b/java/java-impl/src/com/intellij/psi/impl/light/LightClass.java new file mode 100644 index 000000000000..1cc45a66e15e --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/impl/light/LightClass.java @@ -0,0 +1,284 @@ +package com.intellij.psi.impl.light; + +import com.intellij.lang.StdLanguages; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.*; +import com.intellij.psi.impl.PsiClassImplUtil; +import com.intellij.psi.impl.PsiImplUtil; +import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; + +/** + * @author peter + */ +public class LightClass extends LightElement implements PsiClass { + private final PsiClass myDelegate; + + public LightClass(PsiClass delegate) { + super(delegate.getManager(), StdLanguages.JAVA); + myDelegate = delegate; + } + + @NonNls + @Nullable + public String getName() { + return myDelegate.getName(); + } + + @Nullable + public PsiModifierList getModifierList() { + return myDelegate.getModifierList(); + } + + public boolean hasModifierProperty(@Modifier @NonNls @NotNull String name) { + return myDelegate.hasModifierProperty(name); + } + + @Nullable + public PsiDocComment getDocComment() { + return null; + } + + public boolean isDeprecated() { + return myDelegate.isDeprecated(); + } + + public boolean hasTypeParameters() { + return PsiImplUtil.hasTypeParameters(this); + } + + @Nullable + public PsiTypeParameterList getTypeParameterList() { + return myDelegate.getTypeParameterList(); + } + + @NotNull + public PsiTypeParameter[] getTypeParameters() { + return myDelegate.getTypeParameters(); + } + + @NonNls + @Nullable + public String getQualifiedName() { + return myDelegate.getQualifiedName(); + } + + public boolean isInterface() { + return myDelegate.isInterface(); + } + + public boolean isAnnotationType() { + return myDelegate.isAnnotationType(); + } + + public boolean isEnum() { + return myDelegate.isEnum(); + } + + @Nullable + public PsiReferenceList getExtendsList() { + return myDelegate.getExtendsList(); + } + + @Nullable + public PsiReferenceList getImplementsList() { + return myDelegate.getImplementsList(); + } + + @NotNull + public PsiClassType[] getExtendsListTypes() { + return PsiClassImplUtil.getExtendsListTypes(this); + } + + @NotNull + public PsiClassType[] getImplementsListTypes() { + return PsiClassImplUtil.getImplementsListTypes(this); + } + + @Nullable + public PsiClass getSuperClass() { + return myDelegate.getSuperClass(); + } + + public PsiClass[] getInterfaces() { + return myDelegate.getInterfaces(); + } + + @NotNull + @Override + public PsiElement getNavigationElement() { + return myDelegate.getNavigationElement(); + } + + @NotNull + public PsiClass[] getSupers() { + return myDelegate.getSupers(); + } + + @NotNull + public PsiClassType[] getSuperTypes() { + return myDelegate.getSuperTypes(); + } + + @NotNull + public PsiField[] getFields() { + return myDelegate.getFields(); + } + + @NotNull + public PsiMethod[] getMethods() { + return myDelegate.getMethods(); + } + + @NotNull + public PsiMethod[] getConstructors() { + return myDelegate.getConstructors(); + } + + @NotNull + public PsiClass[] getInnerClasses() { + return myDelegate.getInnerClasses(); + } + + @NotNull + public PsiClassInitializer[] getInitializers() { + return myDelegate.getInitializers(); + } + + @NotNull + public PsiField[] getAllFields() { + return myDelegate.getAllFields(); + } + + @NotNull + public PsiMethod[] getAllMethods() { + return myDelegate.getAllMethods(); + } + + @NotNull + public PsiClass[] getAllInnerClasses() { + return myDelegate.getAllInnerClasses(); + } + + @Nullable + public PsiField findFieldByName(@NonNls String name, boolean checkBases) { + return PsiClassImplUtil.findFieldByName(this, name, checkBases); + } + + @Nullable + public PsiMethod findMethodBySignature(PsiMethod patternMethod, boolean checkBases) { + return PsiClassImplUtil.findMethodBySignature(this, patternMethod, checkBases); + } + + @NotNull + public PsiMethod[] findMethodsBySignature(PsiMethod patternMethod, boolean checkBases) { + return PsiClassImplUtil.findMethodsBySignature(this, patternMethod, checkBases); + } + + @NotNull + public PsiMethod[] findMethodsByName(@NonNls String name, boolean checkBases) { + return PsiClassImplUtil.findMethodsByName(this, name, checkBases); + } + + @NotNull + public List> findMethodsAndTheirSubstitutorsByName(@NonNls String name, boolean checkBases) { + return PsiClassImplUtil.findMethodsAndTheirSubstitutorsByName(this, name, checkBases); + } + + @NotNull + public List> getAllMethodsAndTheirSubstitutors() { + return PsiClassImplUtil.getAllWithSubstitutorsByMap(this, PsiMethod.class); + } + + @Nullable + public PsiClass findInnerClassByName(@NonNls String name, boolean checkBases) { + return myDelegate.findInnerClassByName(name, checkBases); + } + + @Nullable + public PsiJavaToken getLBrace() { + return myDelegate.getLBrace(); + } + + @Nullable + public PsiJavaToken getRBrace() { + return myDelegate.getRBrace(); + } + + @Nullable + public PsiIdentifier getNameIdentifier() { + return myDelegate.getNameIdentifier(); + } + + public PsiElement getScope() { + return myDelegate.getScope(); + } + + public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) { + return myDelegate.isInheritor(baseClass, checkDeep); + } + + public boolean isInheritorDeep(PsiClass baseClass, @Nullable PsiClass classToByPass) { + return myDelegate.isInheritorDeep(baseClass, classToByPass); + } + + @Nullable + public PsiClass getContainingClass() { + return myDelegate.getContainingClass(); + } + + @NotNull + public Collection getVisibleSignatures() { + return myDelegate.getVisibleSignatures(); + } + + public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException { + return myDelegate.setName(name); + } + + @Override + public String toString() { + return "PsiClass:" + getName(); + } + + public String getText() { + return myDelegate.getText(); + } + + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof JavaElementVisitor) { + ((JavaElementVisitor)visitor).visitClass(this); + } else { + visitor.visitElement(this); + } + } + + public PsiElement copy() { + return new LightClass(this); + } + + @Override + public PsiFile getContainingFile() { + return myDelegate.getContainingFile(); + } + + public PsiClass getDelegate() { + return myDelegate; + } + + @Override + public PsiElement getContext() { + return myDelegate; + } + + @Override + public boolean isEquivalentTo(PsiElement another) { + return this == another || getDelegate().isEquivalentTo(another); + } +} diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDClassComment.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDClassComment.java index 4cb8c1c6963d..f5828c874c98 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDClassComment.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDClassComment.java @@ -24,7 +24,7 @@ import java.util.ArrayList; * * @author Dmitry Skavish */ -public class JDClassComment extends JDComment { +public class JDClassComment extends JDParamListOwnerComment { public JDClassComment(CommentFormatter formatter) { super(formatter); } @@ -33,6 +33,7 @@ public class JDClassComment extends JDComment { private String version; protected void generateSpecial(String prefix, @NonNls StringBuffer sb) { + super.generateSpecial(prefix, sb); if (!isNull(authorsList)) { for (Object aAuthorsList : authorsList) { String s = (String)aAuthorsList; diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDMethodComment.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDMethodComment.java index 0db0eda70ac4..d9ae93df6461 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDMethodComment.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDMethodComment.java @@ -24,90 +24,20 @@ import java.util.ArrayList; * * @author Dmitry Skavish */ -public class JDMethodComment extends JDComment { +public class JDMethodComment extends JDParamListOwnerComment { public JDMethodComment(CommentFormatter formatter) { super(formatter); } private String returnTag; - private ArrayList parmsList; private ArrayList throwsList; - private static final @NonNls String PARAM_TAG = "@param "; private static final @NonNls String THROWS_TAG = "@throws "; private static final @NonNls String EXCEPTION_TAG = "@exception "; - /** - * Generates parameters or exceptions - * - */ - private void generateList(String prefix, StringBuffer sb, ArrayList list, String tag, - boolean align_comments, - int min_name_length, - int max_name_length, - boolean generate_empty_tags - ) { - int max = 0; - if (align_comments) { - for (Object aList : list) { - NameDesc nd = (NameDesc)aList; - int l = nd.name.length(); - if (isNull(nd.desc) && !generate_empty_tags) continue; - if (l > max && l <= max_name_length) max = l; - } - } - - max = Math.max(max, min_name_length); - - // create filler - StringBuffer fill = new StringBuffer(prefix.length() + tag.length() + max + 1); - fill.append(prefix); - int k = max + 1 + tag.length(); - for (int i = 0; i < k; i++) fill.append(' '); - - for (Object aList1 : list) { - NameDesc nd = (NameDesc)aList1; - if (isNull(nd.desc) && !generate_empty_tags) continue; - if (align_comments) { - sb.append(prefix); - sb.append(tag); - sb.append(nd.name); - - if (nd.name.length() > max_name_length) { - sb.append('\n'); - sb.append(myFormatter.getParser().splitIntoCLines(nd.desc, fill, true)); - } - else { - int len = max - nd.name.length() + 1; - for (int j = 0; j < len; j++) { - sb.append(' '); - } - sb.append(myFormatter.getParser().splitIntoCLines(nd.desc, fill, false)); - } - } - else { - sb.append(myFormatter.getParser().splitIntoCLines(tag + nd.name + " " + nd.desc, prefix, true)); - } - } - } - protected void generateSpecial(String prefix, @NonNls StringBuffer sb) { - if (parmsList != null) { - int before = sb.length(); - generateList(prefix, sb, parmsList, PARAM_TAG, - myFormatter.getSettings().JD_ALIGN_PARAM_COMMENTS, - myFormatter.getSettings().JD_MIN_PARM_NAME_LENGTH, - myFormatter.getSettings().JD_MAX_PARM_NAME_LENGTH, - myFormatter.getSettings().JD_KEEP_EMPTY_PARAMETER - ); - - int size = sb.length() - before; - if (size > 0 && myFormatter.getSettings().JD_ADD_BLANK_AFTER_PARM_COMMENTS) { - sb.append(prefix); - sb.append('\n'); - } - } + super.generateSpecial(prefix, sb); if (returnTag != null) { if (returnTag.trim().length() != 0 || myFormatter.getSettings().JD_KEEP_EMPTY_RETURN) { @@ -140,40 +70,11 @@ public class JDMethodComment extends JDComment { this.returnTag = returnTag; } - public NameDesc getParameter(String name) { - return getNameDesc(name, parmsList); - } - - public void removeParameter(NameDesc nd) { - if (parmsList == null) return; - parmsList.remove(nd); - } - public void removeThrow(NameDesc nd) { if (throwsList == null) return; throwsList.remove(nd); } - private static NameDesc getNameDesc(String name, ArrayList list) { - if (list == null) return null; - for (Object aList : list) { - NameDesc parameter = (NameDesc)aList; - if (parameter.name.equals(name)) return parameter; - } - return null; - } - - public ArrayList getParmsList() { - return parmsList; - } - - public void addParameter(String name, String description) { - if (parmsList == null) { - parmsList = new ArrayList(); - } - parmsList.add(new NameDesc(name, description)); - } - public ArrayList getThrowsList() { return throwsList; } @@ -189,10 +90,6 @@ public class JDMethodComment extends JDComment { return getNameDesc(name, throwsList); } - public void setParmsList(ArrayList parmsList) { - this.parmsList = parmsList; - } - public void setThrowsList(ArrayList throwsList) { this.throwsList = throwsList; } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParamListOwnerComment.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParamListOwnerComment.java new file mode 100644 index 000000000000..04dfefe4d7d6 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParamListOwnerComment.java @@ -0,0 +1,140 @@ +/* + * Copyright 2000-2010 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. + */ + +/* + * User: anna + * Date: 30-Apr-2010 + */ +package com.intellij.psi.impl.source.codeStyle.javadoc; + +import org.jetbrains.annotations.NonNls; + +import java.util.ArrayList; + +public class JDParamListOwnerComment extends JDComment{ + protected ArrayList parmsList; + private static final @NonNls String PARAM_TAG = "@param "; + + public JDParamListOwnerComment(CommentFormatter formatter) { + super(formatter); + } + + @Override + protected void generateSpecial(String prefix, StringBuffer sb) { + if (parmsList != null) { + int before = sb.length(); + generateList(prefix, sb, parmsList, PARAM_TAG, + myFormatter.getSettings().JD_ALIGN_PARAM_COMMENTS, + myFormatter.getSettings().JD_MIN_PARM_NAME_LENGTH, + myFormatter.getSettings().JD_MAX_PARM_NAME_LENGTH, + myFormatter.getSettings().JD_KEEP_EMPTY_PARAMETER + ); + + int size = sb.length() - before; + if (size > 0 && myFormatter.getSettings().JD_ADD_BLANK_AFTER_PARM_COMMENTS) { + sb.append(prefix); + sb.append('\n'); + } + } + } + + public NameDesc getParameter(String name) { + return getNameDesc(name, parmsList); + } + + public void removeParameter(NameDesc nd) { + if (parmsList == null) return; + parmsList.remove(nd); + } + + public ArrayList getParmsList() { + return parmsList; + } + + public void addParameter(String name, String description) { + if (parmsList == null) { + parmsList = new ArrayList(); + } + parmsList.add(new NameDesc(name, description)); + } + + public void setParmsList(ArrayList parmsList) { + this.parmsList = parmsList; + } + + static NameDesc getNameDesc(String name, ArrayList list) { + if (list == null) return null; + for (Object aList : list) { + NameDesc parameter = (NameDesc)aList; + if (parameter.name.equals(name)) return parameter; + } + return null; + } + + /** + * Generates parameters or exceptions + * + */ + protected void generateList(String prefix, StringBuffer sb, ArrayList list, String tag, + boolean align_comments, + int min_name_length, + int max_name_length, + boolean generate_empty_tags + ) { + int max = 0; + if (align_comments) { + for (Object aList : list) { + NameDesc nd = (NameDesc)aList; + int l = nd.name.length(); + if (isNull(nd.desc) && !generate_empty_tags) continue; + if (l > max && l <= max_name_length) max = l; + } + } + + max = Math.max(max, min_name_length); + + // create filler + StringBuffer fill = new StringBuffer(prefix.length() + tag.length() + max + 1); + fill.append(prefix); + int k = max + 1 + tag.length(); + for (int i = 0; i < k; i++) fill.append(' '); + + for (Object aList1 : list) { + NameDesc nd = (NameDesc)aList1; + if (isNull(nd.desc) && !generate_empty_tags) continue; + if (align_comments) { + sb.append(prefix); + sb.append(tag); + sb.append(nd.name); + + if (nd.name.length() > max_name_length) { + sb.append('\n'); + sb.append(myFormatter.getParser().splitIntoCLines(nd.desc, fill, true)); + } + else { + int len = max - nd.name.length() + 1; + for (int j = 0; j < len; j++) { + sb.append(' '); + } + sb.append(myFormatter.getParser().splitIntoCLines(nd.desc, fill, false)); + } + } + else { + sb.append(myFormatter.getParser().splitIntoCLines(tag + nd.name + " " + nd.desc, prefix, true)); + } + } + } +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParser.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParser.java index 0853561f9d29..8136bed7111e 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParser.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParser.java @@ -399,9 +399,9 @@ public class JDParser { }, new TagParser() { boolean parse(String tag, String line, JDComment c) { - boolean isMyTag = c instanceof JDMethodComment && PARAM_TAG.equals(tag); + boolean isMyTag = c instanceof JDParamListOwnerComment && PARAM_TAG.equals(tag); if (isMyTag) { - JDMethodComment mc = (JDMethodComment)c; + JDParamListOwnerComment mc = (JDParamListOwnerComment)c; int idx; for (idx = 0; idx < line.length(); idx++) { char ch = line.charAt(idx); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveCache.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveCache.java index 86a110cef96a..cc16aef88444 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveCache.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveCache.java @@ -98,7 +98,12 @@ public class JavaResolveCache { type = ConcurrencyUtil.cacheOrGet(myCalculatedTypes, expr, type); } if (!type.isValid()) { - LOG.error("Type is invalid: " + type+"; expr: '"+expr+"' is "+(expr.isValid() ? "valid":"invalid")); + if (expr.isValid()) { + LOG.error("Type is invalid: " + type + "; expr: '" + expr + "' is valid"); + } + else { + LOG.error("Expression: '"+expr+"' is invalid, must not be used for getType()"); + } } return type == NULL_TYPE ? null : type; } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/ClassElement.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/ClassElement.java index 9fd76b1a5e5b..2355e79e895b 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/ClassElement.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/ClassElement.java @@ -417,13 +417,26 @@ public class ClassElement extends CompositeElement implements Constants { public static int getMemberOrderWeight(PsiElement member, CodeStyleSettings settings) { if (member instanceof PsiField) { - return member instanceof PsiEnumConstant ? 1 : settings.FIELDS_ORDER_WEIGHT + 1; + if (member instanceof PsiEnumConstant) { + return 1; + } + else { + return ((PsiField)member).hasModifierProperty(PsiModifier.STATIC) ? settings.STATIC_FIELDS_ORDER_WEIGHT + 1 + : settings.FIELDS_ORDER_WEIGHT + 1; + } } else if (member instanceof PsiMethod) { - return ((PsiMethod)member).isConstructor() ? settings.CONSTRUCTORS_ORDER_WEIGHT + 1 : settings.METHODS_ORDER_WEIGHT + 1; + if (((PsiMethod)member).isConstructor()) { + return settings.CONSTRUCTORS_ORDER_WEIGHT + 1; + } + else { + return ((PsiMethod)member).hasModifierProperty(PsiModifier.STATIC) ? settings.STATIC_METHODS_ORDER_WEIGHT + 1 + : settings.METHODS_ORDER_WEIGHT + 1; + } } else if (member instanceof PsiClass) { - return settings.INNER_CLASSES_ORDER_WEIGHT + 1; + return ((PsiClass)member).hasModifierProperty(PsiModifier.STATIC) ? settings.STATIC_INNER_CLASSES_ORDER_WEIGHT + 1 + : settings.INNER_CLASSES_ORDER_WEIGHT + 1; } else { return -1; diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiExpressionListImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiExpressionListImpl.java index 9c5ebeb2b227..aedf71709a7a 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiExpressionListImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiExpressionListImpl.java @@ -128,8 +128,9 @@ public class PsiExpressionListImpl extends CompositePsiElement implements PsiExp } } for (ASTNode child = element.getTreePrev(); child != null; child = child.getTreePrev()) { - if (child.getElementType() == JavaTokenType.COMMA) break; - if (ElementType.EXPRESSION_BIT_SET.contains(child.getElementType())) { + final IElementType t = child.getElementType(); + if (t == JavaTokenType.COMMA) break; + if (ElementType.EXPRESSION_BIT_SET.contains(t) || ElementType.COMMENT_BIT_SET.contains(t)) { TreeElement comma = Factory.createSingleLeafElement(JavaTokenType.COMMA, ",", 0, 1, treeCharTab, getManager()); super.addInternal(comma, comma, child, Boolean.FALSE); break; diff --git a/java/java-impl/src/com/intellij/refactoring/anonymousToInner/AnonymousToInnerDialog.java b/java/java-impl/src/com/intellij/refactoring/anonymousToInner/AnonymousToInnerDialog.java index 3465963524f6..63482459e8f5 100644 --- a/java/java-impl/src/com/intellij/refactoring/anonymousToInner/AnonymousToInnerDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/anonymousToInner/AnonymousToInnerDialog.java @@ -104,7 +104,7 @@ class AnonymousToInnerDialog extends DialogWrapper{ } public JComponent getPreferredFocusedComponent() { - return myNameField; + return myNameField.getFocusableComponent(); } public boolean isMakeStatic() { diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java index ebda6b141cf7..cf4b20a9ade9 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -33,6 +33,7 @@ import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; @@ -598,7 +599,23 @@ public class ExtractMethodProcessor implements MatchProvider { body.add(myElementFactory.createStatementFromText("return false;", null)); } else if (!myHasReturnStatement && hasNormalExit && myOutputVariable != null) { - body.add(returnStatement); + final PsiReturnStatement insertedReturnStatement = (PsiReturnStatement)body.add(returnStatement); + if (myOutputVariables.length == 1) { + final PsiExpression returnValue = insertedReturnStatement.getReturnValue(); + if (returnValue instanceof PsiReferenceExpression) { + final PsiElement resolved = ((PsiReferenceExpression)returnValue).resolve(); + if (resolved instanceof PsiLocalVariable && Comparing.strEqual(((PsiVariable)resolved).getName(), outVariableName)) { + final PsiStatement statement = PsiTreeUtil.getPrevSiblingOfType(insertedReturnStatement, PsiStatement.class); + if (statement instanceof PsiDeclarationStatement) { + final PsiElement[] declaredElements = ((PsiDeclarationStatement)statement).getDeclaredElements(); + if (ArrayUtil.find(declaredElements, resolved) != -1) { + InlineUtil.inlineVariable((PsiVariable)resolved, ((PsiVariable)resolved).getInitializer(), (PsiReferenceExpression)returnValue); + resolved.delete(); + } + } + } + } + } } if (myNullConditionalCheck) { final String varName = myOutputVariable.getName(); diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java index 358d49bcb575..1ee80ece1432 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java @@ -111,7 +111,7 @@ public class ParametersFolder { public boolean isParameterFoldable(@NotNull ParameterTablePanel.VariableData data, @NotNull LocalSearchScope scope, @NotNull final List inputVariables) { - final List mentionedInExpressions = getMentionedExpressions(data.variable, scope); + final List mentionedInExpressions = getMentionedExpressions(data.variable, scope, inputVariables); if (mentionedInExpressions == null) return false; int currentRank = 0; @@ -174,7 +174,7 @@ public class ParametersFolder { } @Nullable - private List getMentionedExpressions(PsiVariable var, LocalSearchScope scope) { + private List getMentionedExpressions(PsiVariable var, LocalSearchScope scope, final List inputVariables) { if (myMentionedInExpressions.containsKey(var)) return myMentionedInExpressions.get(var); final PsiElement[] scopeElements = scope.getScope(); List expressions = null; @@ -194,6 +194,9 @@ public class ParametersFolder { final PsiType expressionType = ((PsiExpression)expression).getType(); if (expressionType != null && expressionType != PsiType.VOID && !(expression.getParent() instanceof PsiExpressionStatement)) { + if (dependsOnLocals(expression, inputVariables)) { + break; + } expressions.add((PsiExpression)expression); } expression = PsiTreeUtil.getParentOfType(expression, PsiExpression.class); @@ -211,6 +214,25 @@ public class ParametersFolder { return expressions; } + private static boolean dependsOnLocals(final PsiElement expression, final List inputVariables) { + final boolean[] localVarsUsed = new boolean[]{false}; + expression.accept(new JavaRecursiveElementWalkingVisitor(){ + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + final PsiElement resolved = expression.resolve(); + if (resolved instanceof PsiVariable) { + final PsiVariable variable = (PsiVariable)resolved; + if (!inputVariables.contains(variable)) { + localVarsUsed[0] = true; + return; + } + } + super.visitReferenceExpression(expression); + } + }); + return localVarsUsed[0]; + } + @NotNull public String getGeneratedCallArgument(@NotNull ParameterTablePanel.VariableData data) { return myExpressions.containsKey(data.variable) ? myExpressions.get(data.variable).getText() : data.variable.getName(); diff --git a/java/java-impl/src/com/intellij/usages/impl/rules/MethodGroupingRule.java b/java/java-impl/src/com/intellij/usages/impl/rules/MethodGroupingRule.java index 09694b709f7c..8846de62d2fb 100644 --- a/java/java-impl/src/com/intellij/usages/impl/rules/MethodGroupingRule.java +++ b/java/java-impl/src/com/intellij/usages/impl/rules/MethodGroupingRule.java @@ -107,7 +107,7 @@ public class MethodGroupingRule implements UsageGroupingRule { } private PsiMethod getMethod() { - return (PsiMethod)myMethodPointer.getElement(); + return myMethodPointer.getElement(); } @NotNull diff --git a/java/java-impl/src/com/intellij/util/xml/impl/ExtendsClassChecker.java b/java/java-impl/src/com/intellij/util/xml/impl/ExtendsClassChecker.java index 5bdba4cb4c3c..c54ff5089a64 100644 --- a/java/java-impl/src/com/intellij/util/xml/impl/ExtendsClassChecker.java +++ b/java/java-impl/src/com/intellij/util/xml/impl/ExtendsClassChecker.java @@ -21,9 +21,10 @@ import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassRe import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReferenceProvider; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.ProcessingContext; import com.intellij.util.ReflectionCache; import com.intellij.util.SmartList; -import com.intellij.util.ProcessingContext; import com.intellij.util.xml.*; import com.intellij.util.xml.highlighting.DomCustomAnnotationChecker; import com.intellij.util.xml.highlighting.DomElementAnnotationHolder; @@ -97,7 +98,7 @@ public class ExtendsClassChecker extends DomCustomAnnotationChecker else if (!allowNonPublic && !value.hasModifierProperty(PsiModifier.PUBLIC)) { list.add(holder.createProblem(element, DomBundle.message("class.is.not.public", value.getQualifiedName()))); } - else if (!hasDefaultConstructor(value)) { + else if (!PsiUtil.hasDefaultConstructor(value, true)) { if (canBeDecorator) { boolean hasConstructor = false; @@ -134,21 +135,6 @@ public class ExtendsClassChecker extends DomCustomAnnotationChecker return list; } - public static boolean hasDefaultConstructor(PsiClass clazz) { - final PsiMethod[] constructors = clazz.getConstructors(); - if (constructors.length > 0) { - for (PsiMethod cls: constructors) { - if ((cls.hasModifierProperty(PsiModifier.PUBLIC) || cls.hasModifierProperty(PsiModifier.PROTECTED)) && cls.getParameterList().getParametersCount() == 0) { - return true; - } - } - } else { - final PsiClass superClass = clazz.getSuperClass(); - return superClass == null || hasDefaultConstructor(superClass); - } - return false; - } - public static List checkExtendsClassInReferences(final GenericDomValue element, final DomElementAnnotationHolder holder) { final Object valueObject = element.getValue(); if (!(valueObject instanceof PsiClass)) return Collections.emptyList(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Link0.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Link0.java index b317f020e162..733cec2da1a9 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Link0.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Link0.java @@ -1,6 +1,6 @@ class Test { /** - * @param ppp see {@link #Test} + * @param ppp see {@link #Test} */ public void i(int ppp) {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/LinkFromInnerClassToSelfMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/LinkFromInnerClassToSelfMethod.java index 728c62bd2142..c8a24ca4ee9d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/LinkFromInnerClassToSelfMethod.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/LinkFromInnerClassToSelfMethod.java @@ -2,7 +2,7 @@ class Test { public void i(int ppp) {} /** - * {@link #foo(int)} + * {@link #foo(int)} * {@link #foo()} * {@link #i(int)} */ diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See0.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See0.java index 8fba319447b9..3b16ac9fd196 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See0.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See0.java @@ -1,6 +1,6 @@ class Test { /** - * @see A#someField + * @see A#someField */ public void i() {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See3.java index 84a76108a039..f5e465172ba3 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See3.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See3.java @@ -1,6 +1,6 @@ class Test { /** - * @see #perform(int) + * @see #perform(int) */ public void i() {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/SeeConstants.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/SeeConstants.java index 04658752ea22..1437f1c27e9e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/SeeConstants.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/SeeConstants.java @@ -3,7 +3,7 @@ public class SeeConstants { public static final String UUU=""; /** - * @see SeeConstants.III + * @see SeeConstants.III * @see SeeConstants#UUU * @param args blah-blah */ diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueBadReference.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueBadReference.java index 955ac0c9f975..1a5b18185041 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueBadReference.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueBadReference.java @@ -1,6 +1,6 @@ class Test { /** - * Value is {@value #badReference} + * Value is {@value #badReference} * @param ppp . */ public void i(int ppp) {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Vararg.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Vararg.java index cfe0f303f84e..604c85627cc2 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Vararg.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Vararg.java @@ -1,7 +1,7 @@ public class Test { /** * @see Test#test(String, int...) - * @see Test#test(String, long...) + * @see Test#test(String, long...) **/ void foo() {} diff --git a/java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithLocalIndex.java b/java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithLocalIndex.java new file mode 100644 index 000000000000..cb850bd94990 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithLocalIndex.java @@ -0,0 +1,9 @@ +class Test { + void foo(String[] ss) { + Integer[] levels = new Integer[]{Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3),}; + Integer[] nextWinNumber = new Integer[6]; + for (Integer level : levels) { + Integer nextWinNum = nextWinNumber[level - 1]; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithLocalIndex_after.java b/java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithLocalIndex_after.java new file mode 100644 index 000000000000..497400c0f37c --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithLocalIndex_after.java @@ -0,0 +1,13 @@ +class Test { + void foo(String[] ss) { + Integer[] levels = new Integer[]{Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3),}; + Integer[] nextWinNumber = new Integer[6]; + newMethod(levels, nextWinNumber); + } + + private void newMethod(Integer[] levels, Integer[] nextWinNumber) { + for (Integer level : levels) { + Integer nextWinNum = nextWinNumber[level - 1]; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/CodeDuplicatesWithOutputValue_after.java b/java/java-tests/testData/refactoring/extractMethod/CodeDuplicatesWithOutputValue_after.java index a5e51c3985bf..9b0dca12e8ea 100644 --- a/java/java-tests/testData/refactoring/extractMethod/CodeDuplicatesWithOutputValue_after.java +++ b/java/java-tests/testData/refactoring/extractMethod/CodeDuplicatesWithOutputValue_after.java @@ -12,8 +12,7 @@ class C { } private List newMethod(Object[] array) { - List l1 = new ArrayList(Arrays.asList(array)); - return l1; + return new ArrayList(Arrays.asList(array)); } String[] getObjects() { diff --git a/java/java-tests/testData/refactoring/extractMethod/FinalOutputVar_after.java b/java/java-tests/testData/refactoring/extractMethod/FinalOutputVar_after.java index 1c73b56ea941..b1ab68d09414 100644 --- a/java/java-tests/testData/refactoring/extractMethod/FinalOutputVar_after.java +++ b/java/java-tests/testData/refactoring/extractMethod/FinalOutputVar_after.java @@ -7,7 +7,6 @@ class C { } private int newMethod() { - final int i = 128; - return i; + return 128; } } \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/InlineCreated2ReturnLocalVariablesOnly.java b/java/java-tests/testData/refactoring/extractMethod/InlineCreated2ReturnLocalVariablesOnly.java new file mode 100644 index 000000000000..91101ceea604 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/InlineCreated2ReturnLocalVariablesOnly.java @@ -0,0 +1,8 @@ +class Test { + void foo() { + int j = 0; + int i = 0; + j = 9; + System.out.println(i); + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/InlineCreated2ReturnLocalVariablesOnly_after.java b/java/java-tests/testData/refactoring/extractMethod/InlineCreated2ReturnLocalVariablesOnly_after.java new file mode 100644 index 000000000000..e7b333b09f46 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/InlineCreated2ReturnLocalVariablesOnly_after.java @@ -0,0 +1,13 @@ +class Test { + void foo() { + int i = newMethod(); + System.out.println(i); + } + + private int newMethod() { + int j = 0; + int i = 0; + j = 9; + return i; + } +} diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBlankLinesTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBlankLinesTest.java index ab7059cb1e8a..e9a2cce69703 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBlankLinesTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBlankLinesTest.java @@ -33,6 +33,7 @@ public class JavaFormatterBlankLinesTest extends AbstractJavaFormatterTest { " fmt.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));\n" + " }\n" + "}", + "class T {\n" + " private final DecimalFormat fmt = new DecimalFormat();\n" + "\n" + @@ -45,4 +46,225 @@ public class JavaFormatterBlankLinesTest extends AbstractJavaFormatterTest { "}"); } + public void testBlankLinesAroundClassMethods() { + // Inspired by IDEA-19408 + getSettings().BLANK_LINES_AROUND_METHOD = 3; + + doTextTest( + "class Test {\n" + + " public boolean flag1() {\n" + + " return false;\n" + + " }public boolean flag2() {\n" + + " return false;\n" + + " }public boolean flag3() {\n" + + " return false;\n" + + " }public boolean flag4() {\n" + + " return false;\n" + + " }\n" + + "}", + + "class Test {\n" + + " public boolean flag1() {\n" + + " return false;\n" + + " }\n" + + "\n" + + "\n" + + "\n" + + " public boolean flag2() {\n" + + " return false;\n" + + " }\n" + + "\n" + + "\n" + + "\n" + + " public boolean flag3() {\n" + + " return false;\n" + + " }\n" + + "\n" + + "\n" + + "\n" + + " public boolean flag4() {\n" + + " return false;\n" + + " }\n" + + "}" + ); + } + + public void testBlankLinesAroundEnumMethods() { + // Inspired by IDEA-19408 + getSettings().BLANK_LINES_AROUND_METHOD = 2; + + doTextTest( + "public enum Wrapping {\n" + + " WRAPPING {public boolean flag1() {\n" + + " return false;\n" + + " }public boolean flag2() {\n" + + " return false;\n" + + " }public boolean flag3() {\n" + + " return false;\n" + + " }public boolean flag4() {\n" + + " return false;\n" + + " }}\n" + + "}", + + "public enum Wrapping {\n" + + " WRAPPING {\n" + + " public boolean flag1() {\n" + + " return false;\n" + + " }\n" + + "\n" + + "\n" + + " public boolean flag2() {\n" + + " return false;\n" + + " }\n" + + "\n" + + "\n" + + " public boolean flag3() {\n" + + " return false;\n" + + " }\n" + + "\n" + + "\n" + + " public boolean flag4() {\n" + + " return false;\n" + + " }\n" + + " }\n" + + "}" + ); + } + + public void testInitializationBlockAndInnerClass() { + // Inspired by IDEA-21191 + getSettings().BLANK_LINES_AROUND_CLASS = 3; + + doTextTest( + "public class FormattingTest {\n" + + " {\n" + + " System.out.println(\"\");\n" + + " }\n" + + " class MyInnerClass1 {\n" + + " }\n" + + " {\n" + + " System.out.println(\"\");\n" + + " }\n" + + " static {\n" + + " System.out.println(\"\");\n" + + " }\n" + + " class MyInnerClass2 {\n" + + " }\n" + + " static {\n" + + " System.out.println(\"\");\n" + + " }\n" + + "}", + + "public class FormattingTest {\n" + + " {\n" + + " System.out.println(\"\");\n" + + " }\n" + + "\n" + + "\n" + + "\n" + + " class MyInnerClass1 {\n" + + " }\n" + + "\n" + + "\n" + + "\n" + + " {\n" + + " System.out.println(\"\");\n" + + " }\n" + + "\n" + + " static {\n" + + " System.out.println(\"\");\n" + + " }\n" + + "\n" + + "\n" + + "\n" + + " class MyInnerClass2 {\n" + + " }\n" + + "\n" + + "\n" + + "\n" + + " static {\n" + + " System.out.println(\"\");\n" + + " }\n" + + "}" + ); + } + + public void testInnerClasses() { + // Inspired by IDEA-21191 + getSettings().BLANK_LINES_AROUND_CLASS = 3; + + doTextTest( + "public class FormattingTest {\n" + + " class MyInnerClass1 {\n" + + " }\n" + + " class MyInnerClass2 {\n" + + " }\n" + + " static class MyInnerClass3 {\n" + + " }\n" + + " static class MyInnerClass4 {\n" + + " }\n" + + " class MyInnerClass5 {\n" + + " }\n" + + "}", + + "public class FormattingTest {\n" + + " class MyInnerClass1 {\n" + + " }\n" + + "\n" + + "\n" + + "\n" + + " class MyInnerClass2 {\n" + + " }\n" + + "\n" + + "\n" + + "\n" + + " static class MyInnerClass3 {\n" + + " }\n" + + "\n" + + "\n" + + "\n" + + " static class MyInnerClass4 {\n" + + " }\n" + + "\n" + + "\n" + + "\n" + + " class MyInnerClass5 {\n" + + " }\n" + + "}" + ); + } + + public void testTopLevelClasses() { + // Inspired by IDEA-21191 + getSettings().BLANK_LINES_AROUND_CLASS = 3; + + doTextTest( + "class Class1 {\n" + + "}\n" + + "public class Class2 {\n" + + "}\n" + + "class Class3 {\n" + + "}\n" + + "class Class4 {\n" + + "}", + + "class Class1 {\n" + + "}\n" + + "\n" + + "\n" + + "\n" + + "public class Class2 {\n" + + "}\n" + + "\n" + + "\n" + + "\n" + + "class Class3 {\n" + + "}\n" + + "\n" + + "\n" + + "\n" + + "class Class4 {\n" + + "}" + ); + } } diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java index c181648e5488..2d4c7709fc01 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java @@ -123,4 +123,36 @@ public class JavaFormatterIndentationTest extends AbstractJavaFormatterTest { " }" ); } + + public void testAlignedSubBlockIndentation() { + getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true; + getSettings().getIndentOptions(StdFileTypes.JAVA).CONTINUATION_INDENT_SIZE = 8; + + // Inspired by IDEA-54671 + doTextTest( + "class Test {\n" + + " public void foo() {\n" + + " test(11\n" + + " + 12\n" + + " + 13,\n" + + " 21\n" + + " + 22\n" + + " + 23\n" + + " )" + + " }\n" + + "}", + + "class Test {\n" + + " public void foo() {\n" + + " test(11\n" + + " + 12\n" + + " + 13,\n" + + " 21\n" + + " + 22\n" + + " + 23\n" + + " )\n" + + " }\n" + + "}" + ); + } } diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterNewLineTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterNewLineTest.java index e5fdee10ca95..3d093a7164f6 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterNewLineTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterNewLineTest.java @@ -163,87 +163,4 @@ public class JavaFormatterNewLineTest extends AbstractJavaFormatterTest { // Inspired by IDEA-17870 doClassTest("public Test(@Qualifier(\"blah\") AType blah){}", "public Test(@Qualifier(\"blah\") AType blah) {\n" + "}"); } - - public void testBlankLinesAroundClassMethods() { - // Inspired by IDEA-19408 - getSettings().BLANK_LINES_AROUND_METHOD = 3; - - doTextTest( - "class Test {\n" + - " public boolean flag1() {\n" + - " return false;\n" + - " }public boolean flag2() {\n" + - " return false;\n" + - " }public boolean flag3() {\n" + - " return false;\n" + - " }public boolean flag4() {\n" + - " return false;\n" + - " }\n" + - "}", - "class Test {\n" + - " public boolean flag1() {\n" + - " return false;\n" + - " }\n" + - "\n" + - "\n" + - "\n" + - " public boolean flag2() {\n" + - " return false;\n" + - " }\n" + - "\n" + - "\n" + - "\n" + - " public boolean flag3() {\n" + - " return false;\n" + - " }\n" + - "\n" + - "\n" + - "\n" + - " public boolean flag4() {\n" + - " return false;\n" + - " }\n" + - "}" - ); - } - - public void testBlankLinesAroundEnumMethods() { - // Inspired by IDEA-19408 - getSettings().BLANK_LINES_AROUND_METHOD = 2; - - doTextTest( - "public enum Wrapping {\n" + - " WRAPPING {public boolean flag1() {\n" + - " return false;\n" + - " }public boolean flag2() {\n" + - " return false;\n" + - " }public boolean flag3() {\n" + - " return false;\n" + - " }public boolean flag4() {\n" + - " return false;\n" + - " }}\n" + - "}", - "public enum Wrapping {\n" + - " WRAPPING {\n" + - " public boolean flag1() {\n" + - " return false;\n" + - " }\n" + - "\n" + - "\n" + - " public boolean flag2() {\n" + - " return false;\n" + - " }\n" + - "\n" + - "\n" + - " public boolean flag3() {\n" + - " return false;\n" + - " }\n" + - "\n" + - "\n" + - " public boolean flag4() {\n" + - " return false;\n" + - " }\n" + - " }\n" + - "}" - ); - } } diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java index e966bbef3ac5..207411699752 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java @@ -310,6 +310,21 @@ public class JavaFormatterTest extends AbstractJavaFormatterTest { "class A {\n" + " void b() {\n" + " for (c) {\n" + " d();\n" + " }\n" + " }\n" + "}"); } + public void testClassComment() throws Exception { + doTextTest("/**\n" + + "* @author smbd\n" + + "* @param some param\n" + + "* @since 1.9\n" + + "*/\n" + + "class Test{}", + "/**\n" + + " * @param some param\n" + + " * @author smbd\n" + + " * @since 1.9\n" + + " */\n" + + "class Test {\n}"); + } + public void testStringBinaryOperation() throws Exception { final CodeStyleSettings settings = getSettings(); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java index 14ec8d979a44..62d407d9a71c 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java @@ -257,6 +257,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doTest(); } + public void testInlineCreated2ReturnLocalVariablesOnly() throws Exception { + doTest(); + } + public void testGuardMethodDuplicates() throws Exception { doDuplicatesTest(); } @@ -404,6 +408,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doTest(); } + public void testArrayAccessWithLocalIndex() throws Exception { + doTest(); + } + public void testArrayAccessWithDuplicates() throws Exception { doDuplicatesTest(); } diff --git a/java/openapi/src/com/intellij/codeInsight/AttachSourcesProvider.java b/java/openapi/src/com/intellij/codeInsight/AttachSourcesProvider.java index a9e0a6b67d11..f0651c6d88e1 100644 --- a/java/openapi/src/com/intellij/codeInsight/AttachSourcesProvider.java +++ b/java/openapi/src/com/intellij/codeInsight/AttachSourcesProvider.java @@ -15,18 +15,19 @@ */ package com.intellij.codeInsight; -import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.LibraryOrderEntry; import com.intellij.openapi.util.ActionCallback; import com.intellij.psi.PsiFile; import java.util.Collection; +import java.util.List; public interface AttachSourcesProvider { - Collection getActions(Library library, PsiFile psiFile); + Collection getActions(List orderEntries, PsiFile psiFile); interface AttachSourcesAction { String getName(); String getBusyText(); - ActionCallback perform(); + ActionCallback perform(List orderEntriesContainingFile); } } diff --git a/java/openapi/src/com/intellij/psi/util/PsiUtil.java b/java/openapi/src/com/intellij/psi/util/PsiUtil.java index 3713fbadef72..1f925d7967d0 100644 --- a/java/openapi/src/com/intellij/psi/util/PsiUtil.java +++ b/java/openapi/src/com/intellij/psi/util/PsiUtil.java @@ -557,11 +557,13 @@ public final class PsiUtil extends PsiUtilBase { } /** + * @param place place to start traversal + * @param aClass level to stop traversal * @return element with static modifier enclosing place and enclosed by aClass (if not null) */ @Nullable public static PsiModifierListOwner getEnclosingStaticElement(PsiElement place, @Nullable PsiClass aClass) { - LOG.assertTrue(aClass == null || !place.isPhysical() || PsiTreeUtil.isAncestor(aClass, place, false)); + LOG.assertTrue(aClass == null || !place.isPhysical() || PsiTreeUtil.isContextAncestor(aClass, place, false)); PsiElement parent = place; while (parent != aClass) { if (parent instanceof PsiFile) break; @@ -785,10 +787,16 @@ public final class PsiUtil extends PsiUtilBase { } public static boolean hasDefaultConstructor(PsiClass clazz) { + return hasDefaultConstructor(clazz, false); + } + + public static boolean hasDefaultConstructor(PsiClass clazz, boolean allowProtected) { final PsiMethod[] constructors = clazz.getConstructors(); if (constructors.length > 0) { for (PsiMethod cls: constructors) { - if (cls.hasModifierProperty(PsiModifier.PUBLIC) && cls.getParameterList().getParametersCount() == 0) { + if ((cls.hasModifierProperty(PsiModifier.PUBLIC) || + allowProtected && cls.hasModifierProperty(PsiModifier.PROTECTED)) && + cls.getParameterList().getParametersCount() == 0) { return true; } } diff --git a/lib/src/apache-maven-2.2.1-src.zip b/lib/src/apache-maven-2.2.1-src.zip new file mode 100644 index 000000000000..e891db6ccc6c Binary files /dev/null and b/lib/src/apache-maven-2.2.1-src.zip differ diff --git a/platform/bootstrap/src/com/intellij/ide/ClassloaderUtil.java b/platform/bootstrap/src/com/intellij/ide/ClassloaderUtil.java index 08fb0ab8e9ca..ca799298e995 100644 --- a/platform/bootstrap/src/com/intellij/ide/ClassloaderUtil.java +++ b/platform/bootstrap/src/com/intellij/ide/ClassloaderUtil.java @@ -181,7 +181,7 @@ public class ClassloaderUtil { final StringTokenizer tokenizer = new StringTokenizer(classpath, File.separator, false); while (tokenizer.hasMoreTokens()) { final String token = tokenizer.nextToken(); - aClasspathElements.add(new File(token).toURL()); + aClasspathElements.add(new File(token).toURI().toURL()); } } else { @@ -217,7 +217,7 @@ public class ClassloaderUtil { final Class aClass = ClassloaderUtil.class; final String selfRoot = PathManager.getResourceRoot(aClass, "/" + aClass.getName().replace('.', '/') + ".class"); - final URL selfRootUrl = new File(selfRoot).getAbsoluteFile().toURL(); + final URL selfRootUrl = new File(selfRoot).getAbsoluteFile().toURI().toURL(); classPath.add(selfRootUrl); final File libFolder = new File(aFolderPath + File.separator + "lib"); @@ -238,7 +238,7 @@ public class ClassloaderUtil { if (!isJarOrZip(file)) { continue; } - final URL url = file.toURL(); + final URL url = file.toURI().toURL(); if (selfRootUrl.equals(url)) { continue; } @@ -262,7 +262,7 @@ public class ClassloaderUtil { final StringTokenizer tokenizer = new StringTokenizer(System.getProperty("idea.additional.classpath", ""), File.pathSeparator, false); while (tokenizer.hasMoreTokens()) { String pathItem = tokenizer.nextToken(); - classPath.add(new File(pathItem).toURL()); + classPath.add(new File(pathItem).toURI().toURL()); } } catch (MalformedURLException e) { @@ -274,4 +274,4 @@ public class ClassloaderUtil { public static boolean isLoadingOfExternalPluginsDisabled() { return !"true".equalsIgnoreCase(System.getProperty("idea.plugins.load", "true")); } -} \ No newline at end of file +} diff --git a/platform/icons/src/nodes/errorMark.png b/platform/icons/src/nodes/errorMark.png new file mode 100644 index 000000000000..ff911920fa37 Binary files /dev/null and b/platform/icons/src/nodes/errorMark.png differ diff --git a/platform/icons/src/process/step_mask.png b/platform/icons/src/process/step_mask.png new file mode 100644 index 000000000000..f1e7c3e32eeb Binary files /dev/null and b/platform/icons/src/process/step_mask.png differ diff --git a/platform/lang-api/src/com/intellij/codeInspection/ProblemsHolder.java b/platform/lang-api/src/com/intellij/codeInspection/ProblemsHolder.java index ba1705c8497e..c01d4dba74c8 100644 --- a/platform/lang-api/src/com/intellij/codeInspection/ProblemsHolder.java +++ b/platform/lang-api/src/com/intellij/codeInspection/ProblemsHolder.java @@ -179,6 +179,10 @@ public class ProblemsHolder { return myOnTheFly; } + public PsiFile getFile() { + return myFile; + } + public final Project getProject() { return myManager.getProject(); } diff --git a/platform/lang-api/src/com/intellij/execution/DefaultExecutionResult.java b/platform/lang-api/src/com/intellij/execution/DefaultExecutionResult.java index e46328541da1..e236c63676ec 100644 --- a/platform/lang-api/src/com/intellij/execution/DefaultExecutionResult.java +++ b/platform/lang-api/src/com/intellij/execution/DefaultExecutionResult.java @@ -19,6 +19,7 @@ import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.ui.ExecutionConsole; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.util.IconLoader; import org.jetbrains.annotations.NotNull; @@ -78,7 +79,7 @@ public class DefaultExecutionResult implements ExecutionResult { return myProcessHandler; } - public static class StopAction extends AnAction { + public static class StopAction extends AnAction implements DumbAware { private final ProcessHandler myProcessHandler; public StopAction(final ProcessHandler processHandler) { diff --git a/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java b/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java index 28f6e0fa8060..81edd11967a7 100644 --- a/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java +++ b/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java @@ -202,6 +202,7 @@ public class EnvironmentVariablesComponent extends LabeledComponent envs = new LinkedHashMap(); for (EnvironmentVariable variable : myEnvVariablesTable.getEnvironmentVariables()) { envs.put(variable.getName(), variable.getValue()); diff --git a/platform/lang-api/src/com/intellij/execution/util/EnvVariablesTable.java b/platform/lang-api/src/com/intellij/execution/util/EnvVariablesTable.java index 1d7ac1842e3d..da7ed7a7fc0c 100644 --- a/platform/lang-api/src/com/intellij/execution/util/EnvVariablesTable.java +++ b/platform/lang-api/src/com/intellij/execution/util/EnvVariablesTable.java @@ -131,6 +131,10 @@ public class EnvVariablesTable extends Observable { return myVariables; } + public void stopEditing() { + myTableVeiw.stopEditing(); + } + public void refreshValues() { myTableVeiw.getComponent().repaint(); } diff --git a/platform/lang-api/src/com/intellij/find/FindModel.java b/platform/lang-api/src/com/intellij/find/FindModel.java index f24c7e0a8467..c3c191568012 100644 --- a/platform/lang-api/src/com/intellij/find/FindModel.java +++ b/platform/lang-api/src/com/intellij/find/FindModel.java @@ -18,7 +18,6 @@ package com.intellij.find; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.psi.search.SearchScope; -import com.intellij.util.text.StringSearcher; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -57,6 +56,7 @@ public class FindModel extends UserDataHolderBase implements Cloneable { private String fileFilter; private String customScopeName; private SearchScope customScope; + private boolean isCustomScope = false; /** * Gets the Preserve Case flag. @@ -107,6 +107,7 @@ public class FindModel extends UserDataHolderBase implements Cloneable { moduleName = model.moduleName; customScopeName = model.customScopeName; customScope = model.customScope; + isCustomScope = model.isCustomScope; isFindAll = model.isFindAll; isInCommentsOnly = model.isInCommentsOnly; @@ -594,6 +595,14 @@ public class FindModel extends UserDataHolderBase implements Cloneable { this.customScope = customScope; } + public boolean isCustomScope() { + return isCustomScope; + } + + public void setCustomScope(boolean customScope) { + isCustomScope = customScope; + } + public boolean isInStringLiteralsOnly() { return isInStringLiteralsOnly; } diff --git a/platform/lang-api/src/com/intellij/psi/PsiElementResolveResult.java b/platform/lang-api/src/com/intellij/psi/PsiElementResolveResult.java index 129bfff446bf..3d43bc2b55bf 100644 --- a/platform/lang-api/src/com/intellij/psi/PsiElementResolveResult.java +++ b/platform/lang-api/src/com/intellij/psi/PsiElementResolveResult.java @@ -18,6 +18,9 @@ package com.intellij.psi; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; /** * Trivial implementation of {@link ResolveResult}. @@ -67,4 +70,15 @@ public class PsiElementResolveResult implements ResolveResult{ public String toString() { return "PsiElementResolveResult: " + (myElement instanceof PsiNamedElement ? ((PsiNamedElement)myElement).getName() : myElement.getText()); } + + public static ResolveResult[] createResults(@Nullable Collection elements) { + if (elements == null || elements.isEmpty()) return EMPTY_ARRAY; + + final ResolveResult[] results = new ResolveResult[elements.size()]; + int i = 0; + for (PsiElement element : elements) { + results[i++] = new PsiElementResolveResult(element); + } + return results; + } } diff --git a/platform/lang-api/src/com/intellij/psi/PsiPolyVariantReferenceBase.java b/platform/lang-api/src/com/intellij/psi/PsiPolyVariantReferenceBase.java index 50b4e585eee3..aa2d99396790 100644 --- a/platform/lang-api/src/com/intellij/psi/PsiPolyVariantReferenceBase.java +++ b/platform/lang-api/src/com/intellij/psi/PsiPolyVariantReferenceBase.java @@ -41,4 +41,15 @@ public abstract class PsiPolyVariantReferenceBase extends ResolveResult[] resolveResults = multiResolve(false); return resolveResults.length == 1 ? resolveResults[0].getElement() : null; } + + @Override + public boolean isReferenceTo(PsiElement element) { + final ResolveResult[] results = multiResolve(false); + for (ResolveResult result : results) { + if (getElement().getManager().areElementsEquivalent(result.getElement(), element)) { + return true; + } + } + return false; + } } diff --git a/platform/lang-api/src/com/intellij/psi/WalkingState.java b/platform/lang-api/src/com/intellij/psi/WalkingState.java index d6ac55d5daad..5270d355219c 100644 --- a/platform/lang-api/src/com/intellij/psi/WalkingState.java +++ b/platform/lang-api/src/com/intellij/psi/WalkingState.java @@ -21,7 +21,7 @@ import org.jetbrains.annotations.NotNull; /** * @author cdr */ -public abstract class WalkingState { +public class WalkingState { public interface TreeGuide { T getNextSibling(@NotNull T element); T getPrevSibling(@NotNull T element); @@ -33,9 +33,9 @@ public abstract class WalkingState { private final TreeGuide myWalker; private boolean stopped; - public abstract void elementFinished(@NotNull T element); + public void elementFinished(@NotNull T element) {} - protected WalkingState(@NotNull TreeGuide delegate) { + public WalkingState(@NotNull TreeGuide delegate) { myWalker = delegate; } @@ -100,4 +100,4 @@ public abstract class WalkingState { public void stopWalking() { stopped = true; } -} \ No newline at end of file +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java index 516ac66706b7..8fc81103785f 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java @@ -787,10 +787,13 @@ public class CodeStyleSettings implements Cloneable, JDOMExternalizable { //----------------- ORDER OF MEMBERS ------------------ - public int FIELDS_ORDER_WEIGHT = 1; - public int CONSTRUCTORS_ORDER_WEIGHT = 2; - public int METHODS_ORDER_WEIGHT = 3; - public int INNER_CLASSES_ORDER_WEIGHT = 4; + public int STATIC_FIELDS_ORDER_WEIGHT = 1; + public int FIELDS_ORDER_WEIGHT = 2; + public int CONSTRUCTORS_ORDER_WEIGHT = 3; + public int STATIC_METHODS_ORDER_WEIGHT = 4; + public int METHODS_ORDER_WEIGHT = 5; + public int STATIC_INNER_CLASSES_ORDER_WEIGHT = 6; + public int INNER_CLASSES_ORDER_WEIGHT = 7; //----------------- WRAPPING --------------------------- public int RIGHT_MARGIN = 120; diff --git a/platform/lang-api/src/com/intellij/psi/search/LocalSearchScope.java b/platform/lang-api/src/com/intellij/psi/search/LocalSearchScope.java index 2742ae66ad75..79436963175e 100644 --- a/platform/lang-api/src/com/intellij/psi/search/LocalSearchScope.java +++ b/platform/lang-api/src/com/intellij/psi/search/LocalSearchScope.java @@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -137,9 +138,12 @@ public class LocalSearchScope extends SearchScope { return ((GlobalSearchScope)scope2).intersectWith(this); } + @Nullable private static PsiElement intersectScopeElements(PsiElement element1, PsiElement element2) { if (PsiTreeUtil.isContextAncestor(element1, element2, false)) return element2; if (PsiTreeUtil.isContextAncestor(element2, element1, false)) return element1; + if (PsiTreeUtil.isAncestor(element1, element2, false)) return element2; + if (PsiTreeUtil.isAncestor(element2, element1, false)) return element1; return null; } diff --git a/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java b/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java index 559847e5ad55..08690cec1fd5 100644 --- a/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java @@ -161,6 +161,8 @@ public abstract class CodeStyleAbstractPanel implements Disposable { myTextToReformat = myEditor.getDocument().getText(); } + int currOffs = myEditor.getScrollingModel().getVerticalScrollOffset(); + final Project finalProject = getCurrentProject(); CommandProcessor.getInstance().executeCommand(finalProject, new Runnable() { public void run() { @@ -169,6 +171,7 @@ public abstract class CodeStyleAbstractPanel implements Disposable { }, null, null); myEditor.getSettings().setRightMargin(getRightMargin()); myLastDocumentModificationStamp = myEditor.getDocument().getModificationStamp(); + myEditor.getScrollingModel().scrollVertically(currOffs); } private void replaceText(final Project project) { @@ -201,7 +204,8 @@ public abstract class CodeStyleAbstractPanel implements Disposable { }); } - protected abstract void prepareForReformat(PsiFile psiFile); + protected void prepareForReformat(PsiFile psiFile) { + } protected PsiFile createFileFromText(Project project, String text) { PsiFile psiFile = PsiFileFactory.getInstance(project) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonTooltipUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonTooltipUtil.java index a5e5000b4e7c..3424b514a620 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonTooltipUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonTooltipUtil.java @@ -41,8 +41,8 @@ public class DaemonTooltipUtil { public static void showInfoTooltip(@NotNull final HighlightInfo info, final Editor editor, final int defaultOffset, final int currentWidth) { if (info.toolTip == null) return; Rectangle visibleArea = editor.getScrollingModel().getVisibleArea(); - int endOffset = info.highlighter.getEndOffset(); - int startOffset = info.highlighter.getStartOffset(); + int startOffset = info.getActualStartOffset(); + int endOffset = info.getActualEndOffset(); Point top = editor.logicalPositionToXY(editor.offsetToLogicalPosition(startOffset)); Point bottom = editor.logicalPositionToXY(editor.offsetToLogicalPosition(endOffset)); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ErrorStripeHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ErrorStripeHandler.java index 0618614e2273..a40325f6d283 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ErrorStripeHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ErrorStripeHandler.java @@ -21,8 +21,6 @@ import com.intellij.openapi.editor.ex.ErrorStripeEvent; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.project.Project; -import java.util.List; - public class ErrorStripeHandler extends ErrorStripeAdapter { private final Project myProject; @@ -39,14 +37,9 @@ public class ErrorStripeHandler extends ErrorStripeAdapter { } } - private HighlightInfo findInfo(RangeHighlighter highlighter) { - List highlights = DaemonCodeAnalyzerImpl.getHighlights(highlighter.getDocument(), myProject); - if (highlights == null) return null; - for (HighlightInfo info : highlights) { - if (info.highlighter == highlighter) { - return info; - } - } + private static HighlightInfo findInfo(final RangeHighlighter highlighter) { + Object o = highlighter.getErrorStripeTooltip(); + if (o instanceof HighlightInfo) return (HighlightInfo)o; return null; } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java index 9c272a2bca65..cfc4c797cbbb 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java @@ -160,11 +160,11 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP } if (elements != null) { result.addAll(collectHighlights(elements, progress, filtered)); - addInjectedPsiHighlights(elements, progress); + if (!addInjectedPsiHighlights(elements, progress)) throw new ProcessCanceledException(); } if (!isDumbMode()) { - result.addAll(highlightTodos(myFile, myDocument.getCharsSequence(), myStartOffset, myEndOffset)); + result.addAll(highlightTodos(myFile, myDocument.getCharsSequence(), myStartOffset, myEndOffset, progress)); } if (myUpdateAll) { @@ -177,7 +177,8 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP myHighlights = result; } - private void addInjectedPsiHighlights(@NotNull final List elements, final ProgressIndicator progress) { + // returns false if canceled + private boolean addInjectedPsiHighlights(@NotNull final List elements, final ProgressIndicator progress) { List injected = InjectedLanguageUtil.getCachedInjectedDocuments(myFile); Collection hosts = new THashSet(elements.size() + injected.size()); @@ -216,10 +217,10 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP } }, false); } - if (injectedFiles.isEmpty()) return; + if (injectedFiles.isEmpty()) return true; final InjectedLanguageManager injectedLanguageManager = InjectedLanguageManager.getInstance(myProject); - JobUtil.invokeConcurrentlyUnderMyProgress(injectedFiles, new Processor() { + return JobUtil.invokeConcurrentlyUnderMyProgress(new ArrayList(injectedFiles), new Processor() { public boolean process(final PsiFile injectedPsi) { DocumentWindow documentWindow = (DocumentWindow)PsiDocumentManager.getInstance(myProject).getCachedDocument(injectedPsi); HighlightInfoHolder holder = createInfoHolder(injectedPsi); @@ -248,7 +249,7 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP } if (!isDumbMode()) { - Collection todos = highlightTodos(injectedPsi, injectedPsi.getText(), 0, injectedPsi.getTextLength()); + Collection todos = highlightTodos(injectedPsi, injectedPsi.getText(), 0, injectedPsi.getTextLength(), progress); for (HighlightInfo info : todos) { addPatchedInfos(info, injectedPsi, documentWindow, injectedLanguageManager, null); } @@ -326,7 +327,7 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP return textRange; } - private void runHighlightVisitosForInjected(final PsiFile injectedPsi, final HighlightInfoHolder holder, final ProgressIndicator progress) { + private void runHighlightVisitosForInjected(@NotNull PsiFile injectedPsi, @NotNull final HighlightInfoHolder holder, @NotNull final ProgressIndicator progress) { HighlightVisitor[] visitors = createHighlightVisitors(); try { HighlightVisitor[] filtered = filterVisitors(visitors, injectedPsi); @@ -541,7 +542,11 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP return new HighlightInfoHolder(file, filters); } - private static Collection highlightTodos(PsiFile file, CharSequence text, int startOffset, int endOffset) { + private static Collection highlightTodos(@NotNull PsiFile file, + @NotNull CharSequence text, + int startOffset, + int endOffset, + @NotNull ProgressIndicator progress) { PsiManager psiManager = file.getManager(); PsiSearchHelper helper = psiManager.getSearchHelper(); TodoItem[] todoItems = helper.findTodoItems(file, startOffset, endOffset); @@ -549,6 +554,7 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP List list = new ArrayList(todoItems.length); for (TodoItem todoItem : todoItems) { + progress.checkCanceled(); TextRange range = todoItem.getTextRange(); String description = text.subSequence(range.getStartOffset(), range.getEndOffset()).toString(); TextAttributes attributes = todoItem.getPattern().getAttributes().getTextAttributes(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java index 001b2b27383b..ea4001491827 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java @@ -39,6 +39,7 @@ import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.util.ProgressWrapper; @@ -192,7 +193,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); LOG.assertTrue(indicator != null); - JobUtil.invokeConcurrentlyUnderMyProgress(tools, new Processor() { + boolean result = JobUtil.invokeConcurrentlyUnderMyProgress(tools, new Processor() { public boolean process(final LocalInspectionTool tool) { final ProgressManager progressManager = ProgressManager.getInstance(); indicator.checkCanceled(); @@ -223,6 +224,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass return true; } }, "Inspection tools"); + if (!result) throw new ProcessCanceledException(); indicator.checkCanceled(); inspectInjectedPsi(elements, tools); @@ -242,12 +244,12 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass } }, false); } - JobUtil.invokeConcurrentlyUnderMyProgress(injected, new Processor() { + if (!JobUtil.invokeConcurrentlyUnderMyProgress(new ArrayList(injected), new Processor() { public boolean process(final PsiFile injectedPsi) { inspectInjectedPsi(injectedPsi, myInjectedPsiInspectionResults, tools); return true; } - }, "Inspect injected fragments"); + }, "Inspect injected fragments")) throw new ProcessCanceledException(); } public Collection getHighlights() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java index 22938eab8868..3544c091d703 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java @@ -21,7 +21,7 @@ import com.intellij.codeHighlighting.Pass; import com.intellij.codeHighlighting.TextEditorHighlightingPass; import com.intellij.concurrency.Job; import com.intellij.concurrency.JobImpl; -import com.intellij.concurrency.JobScheduler; +import com.intellij.concurrency.JobUtil; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -39,7 +39,6 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ConcurrencyUtil; @@ -66,7 +65,6 @@ public abstract class PassExecutorService implements Disposable { public PassExecutorService(Project project) { myProject = project; - Disposer.register(project, this); } public void dispose() { @@ -81,7 +79,8 @@ public abstract class PassExecutorService implements Disposable { if (waitForTermination) { for (Job job : mySubmittedPasses.values()) { try { - if (!job.isDone()) ((JobImpl)job).waitForTermination(); + JobImpl ji = (JobImpl)job; + if (!job.isDone()) ji.waitForTermination(ji.getTasks()); } catch (Throwable throwable) { LOG.error(throwable); @@ -263,9 +262,7 @@ public abstract class PassExecutorService implements Disposable { private void submit(ScheduledPass pass) { if (!pass.myUpdateProgress.isCanceled()) { - Job job = JobScheduler.getInstance().createJob(pass.myPass.toString(), pass.myJobPriority); - job.addTask(pass); - job.schedule(); + Job job = JobUtil.submitToJobThread(pass, pass.myJobPriority); mySubmittedPasses.put(pass, job); } } @@ -440,7 +437,9 @@ public abstract class PassExecutorService implements Disposable { public List getAllSubmittedPasses() { ArrayList result = new ArrayList(mySubmittedPasses.size()); for (ScheduledPass scheduledPass : mySubmittedPasses.keySet()) { - result.add(scheduledPass.myPass); + if (!scheduledPass.myUpdateProgress.isCanceled()) { + result.add(scheduledPass.myPass); + } } return result; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/WholeFileLocalInspectionsPassFactory.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/WholeFileLocalInspectionsPassFactory.java index 9541cf9a1c84..cbfdac182a4e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/WholeFileLocalInspectionsPassFactory.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/WholeFileLocalInspectionsPassFactory.java @@ -22,12 +22,12 @@ import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory; import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar; import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.ex.InspectionProfileWrapper; +import com.intellij.openapi.Disposable; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.Disposable; import com.intellij.profile.Profile; import com.intellij.profile.ProfileChangeAdapter; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; @@ -106,4 +106,4 @@ public class WholeFileLocalInspectionsPassFactory extends AbstractProjectCompone }; } -} \ No newline at end of file +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/DefaultHighlightVisitor.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/DefaultHighlightVisitor.java index 096e013ef036..ffc0a9dcfec9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/DefaultHighlightVisitor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/DefaultHighlightVisitor.java @@ -58,12 +58,10 @@ public class DefaultHighlightVisitor implements HighlightVisitor, DumbAware { public static final ExtensionPointName FILTER_EP_NAME = ExtensionPointName.create("com.intellij.highlightErrorFilter"); private final HighlightErrorFilter[] myErrorFilters; private final Project myProject; - private final boolean myDumb; public DefaultHighlightVisitor(Project project) { myProject = project; myErrorFilters = Extensions.getExtensions(FILTER_EP_NAME, project); - myDumb = DumbService.getInstance(myProject).isDumb(); } public boolean suitableForFile(final PsiFile file) { @@ -122,10 +120,11 @@ public class DefaultHighlightVisitor implements HighlightVisitor, DumbAware { private void runAnnotators(final PsiElement element, HighlightInfoHolder holder, final AnnotationHolderImpl annotationHolder) { List annotators = cachedAnnotators.get(element.getLanguage()); if (annotators.isEmpty()) return; + final boolean dumb = DumbService.getInstance(myProject).isDumb(); JobUtil.invokeConcurrentlyUnderMyProgress(annotators, new Processor() { public boolean process(Annotator annotator) { - if (myDumb && !(annotator instanceof DumbAware)) { + if (dumb && !(annotator instanceof DumbAware)) { return true; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BackspaceHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BackspaceHandler.java index a09d11e78f0f..3625fdee6ce7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BackspaceHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BackspaceHandler.java @@ -35,6 +35,7 @@ import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -148,22 +149,22 @@ public class BackspaceHandler extends EditorWriteActionHandler { return editables.size() == 1 && editables.get(0).equals(rangeToEdit); } + @Nullable public static LogicalPosition getBackspaceUnindentPosition(final PsiFile file, final Editor editor) { if (editor.getSelectionModel().hasSelection() || editor.getSelectionModel().hasBlockSelection()) return null; - LogicalPosition caretPos = editor.getCaretModel().getLogicalPosition(); + final LogicalPosition caretPos = editor.getCaretModel().getLogicalPosition(); if (caretPos.line == 0 || caretPos.column == 0) { return null; } - int lineStartOffset = editor.getDocument().getLineStartOffset(caretPos.line); - int lineEndOffset = lineStartOffset + caretPos.column; + final int startCheckRange = editor.getDocument().getLineStartOffset(caretPos.line); + final int endCheckRange = startCheckRange + caretPos.column; - CharSequence charSeq = editor.getDocument().getCharsSequence(); - // smart backspace is activated only if all characters in the caret line - // are whitespace characters - for(int pos=lineStartOffset; pos job = JobScheduler.getInstance().createJob("Brace highlighter", Job.DEFAULT_PRIORITY); - job.addTask(new Runnable() { + JobUtil.submitToJobThread(new Runnable() { public void run() { if (isReallyDisposed(editor, project)) return; final PsiFile injected = ApplicationManager.getApplication().runReadAction(new Computable() { @@ -114,8 +113,7 @@ public class BraceHighlightingHandler { } }, ModalityState.stateForComponent(editor.getComponent())); } - }); - job.schedule(); + }, Job.DEFAULT_PRIORITY); } private static boolean isReallyDisposed(Editor editor, Project project) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java b/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java index 90a937834fde..3a73d9285f9a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java @@ -61,7 +61,7 @@ public class CustomTemplateCallback { fixInitialState(); } - @Nullable + @NotNull public PsiElement getContext() { return getContext(myFile, myStartOffset > 0 ? myStartOffset - 1 : myStartOffset); } @@ -231,7 +231,8 @@ public class CustomTemplateCallback { myEditor.getDocument().deleteString(caretAt - key.length(), caretAt); } - public static PsiElement getContext(PsiFile file, int offset) { + @NotNull + public static PsiElement getContext(@NotNull PsiFile file, int offset) { PsiElement element = null; if (!InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file)) { element = InjectedLanguageUtil.findInjectedElementNoCommit(file, offset); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java index 24e7df4d9cdd..720fb1d6a01d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java @@ -893,17 +893,10 @@ public class TemplateState implements Disposable { TextAttributes attributes = isSelected ? new TextAttributes(null, null, Color.red, EffectType.BOXED, Font.PLAIN) : new TextAttributes(); TextAttributes endAttributes = new TextAttributes(); - RangeHighlighter segmentHighlighter; int start = mySegments.getSegmentStart(segmentNumber); int end = mySegments.getSegmentEnd(segmentNumber); - if (isEnd) { - segmentHighlighter = myEditor.getMarkupModel() - .addRangeHighlighter(start, end, HighlighterLayer.LAST + 1, endAttributes, HighlighterTargetArea.EXACT_RANGE); - } - else { - segmentHighlighter = - myEditor.getMarkupModel().addRangeHighlighter(start, end, HighlighterLayer.LAST + 1, attributes, HighlighterTargetArea.EXACT_RANGE); - } + RangeHighlighter segmentHighlighter = myEditor.getMarkupModel() + .addRangeHighlighter(start, end, HighlighterLayer.LAST + 1, isEnd ? endAttributes : attributes, HighlighterTargetArea.EXACT_RANGE); segmentHighlighter.setGreedyToLeft(true); segmentHighlighter.setGreedyToRight(true); return segmentHighlighter; diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorProviderInspection.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorProviderInspection.java index b56965123654..a6f434de965c 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorProviderInspection.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorProviderInspection.java @@ -21,6 +21,7 @@ import com.intellij.codeInspection.reference.RefElement; import com.intellij.codeInspection.reference.RefEntity; import com.intellij.codeInspection.reference.RefModule; import com.intellij.codeInspection.reference.RefVisitor; +import com.intellij.codeInspection.ui.ProblemDescriptionNode; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.components.PathMacroManager; import com.intellij.openapi.diagnostic.Logger; @@ -262,8 +263,8 @@ public abstract class DescriptorProviderInspection extends InspectionTool implem for (CommonProblemDescriptor description : descriptions) { @NonNls final String template = description.getDescriptionTemplate(); int line = description instanceof ProblemDescriptor ? ((ProblemDescriptor)description).getLineNumber() : -1; - final String text = description instanceof ProblemDescriptor ? ((ProblemDescriptor)description).getPsiElement().getText() : ""; - @NonNls String problemText = StringUtil.replace(StringUtil.replace(template, "#ref", StringUtil.quoteReplacement(text)), " #loc ", " "); + final PsiElement psiElement = description instanceof ProblemDescriptor ? ((ProblemDescriptor)description).getPsiElement() : null; + @NonNls String problemText = StringUtil.replace(StringUtil.replace(template, "#ref", psiElement != null ? ProblemDescriptionNode.extractHighlightedText(description, psiElement): "") , " #loc ", " "); Element element = refEntity.getRefManager().export(refEntity, parentNode, line); @NonNls Element problemClassElement = new Element(InspectionsBundle.message("inspection.export.results.problem.element.tag")); diff --git a/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java b/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java new file mode 100644 index 000000000000..142bbfc399b2 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java @@ -0,0 +1,323 @@ +/* + * Copyright 2000-2010 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.execution; + +import com.intellij.execution.process.OSProcessHandler; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.ide.errorTreeView.NewErrorTreeViewPanel; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.ToolWindowId; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.ui.content.Content; +import com.intellij.ui.content.ContentFactory; +import com.intellij.ui.content.MessageView; +import com.intellij.util.Function; +import com.intellij.util.NotNullFunction; +import com.intellij.util.concurrency.Semaphore; +import com.intellij.util.ui.ErrorTreeView; +import com.intellij.util.ui.MessageCategory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * + * @author: Roman Chernyatchik + * @date: Oct 4, 2007 + */ +public class ExecutionHelper { + private static final Logger LOG = Logger.getInstance(ExecutionHelper.class.getName()); + + private ExecutionHelper() { + } + + public static void showErrors(@NotNull final Project myProject, + @NotNull final List exceptionList, + @NotNull final String tabDisplayName, + @Nullable final VirtualFile file) { + if (ApplicationManager.getApplication().isUnitTestMode() && !exceptionList.isEmpty()) { + throw new RuntimeException(exceptionList.get(0)); + } + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + if (myProject.isDisposed()) return; + if (exceptionList.isEmpty()) { + removeContents(null, myProject, tabDisplayName); + return; + } + + final RailsErrorViewPanel errorTreeView = new RailsErrorViewPanel(myProject); + try { + openMessagesView(errorTreeView, myProject, tabDisplayName); + } + catch (NullPointerException e) { + final StringBuilder builder = new StringBuilder(); + builder.append("Exceptions occured:"); + for (final Exception exception : exceptionList) { + builder.append("\n"); + builder.append(exception.getMessage()); + } + Messages.showErrorDialog(builder.toString(), "Execution Error"); + return; + } + for (final Exception exception : exceptionList) { + String[] messages = new String[]{exception.getMessage()}; + if (messages.length == 0) messages = new String[]{"Unknown Error"}; + errorTreeView.addMessage(MessageCategory.ERROR, messages, file, -1, -1, null); + } + + ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.MESSAGES_WINDOW).activate(null); + } + }); + } + + private static void openMessagesView(@NotNull final RailsErrorViewPanel errorTreeView, + @NotNull final Project myProject, + @NotNull final String tabDisplayName) { + CommandProcessor commandProcessor = CommandProcessor.getInstance(); + commandProcessor.executeCommand(myProject, new Runnable() { + public void run() { + final MessageView messageView = ServiceManager.getService(myProject, MessageView.class); + final Content content = ContentFactory.SERVICE.getInstance().createContent(errorTreeView, tabDisplayName, true); + messageView.getContentManager().addContent(content); + Disposer.register(content, errorTreeView); + messageView.getContentManager().setSelectedContent(content); + removeContents(content, myProject, tabDisplayName); + } + }, "Open message view", null); + } + + private static void removeContents(@Nullable final Content notToRemove, + @NotNull final Project myProject, + @NotNull final String tabDisplayName) { + MessageView messageView = ServiceManager.getService(myProject, MessageView.class); + Content[] contents = messageView.getContentManager().getContents(); + for (Content content : contents) { + LOG.assertTrue(content != null); + if (content.isPinned()) continue; + if (tabDisplayName.equals(content.getDisplayName()) && content != notToRemove) { + ErrorTreeView listErrorView = (ErrorTreeView)content.getComponent(); + if (listErrorView != null) { + if (messageView.getContentManager().removeContent(content, true)) { + content.release(); + } + } + } + } + } + + @Nullable + public static ProcessHandler findRunningConsole(final Project project, + @NotNull final NotNullFunction cmdLineMatcher) { + final ProcessHandler[] processes = ExecutionManager.getInstance(project).getRunningProcesses(); + for (ProcessHandler process : processes) { + if (process instanceof OSProcessHandler && !process.isProcessTerminated()) { + final String commandLine = ((OSProcessHandler)process).getCommandLine(); + if (cmdLineMatcher.fun(commandLine).booleanValue()) { + return process; + } + } + } + return null; + } + + public static class RailsErrorViewPanel extends NewErrorTreeViewPanel { + public RailsErrorViewPanel(final Project project) { + super(project, null); + } + + protected boolean canHideWarnings() { + return false; + } + } + + + public static void executeExternalProcess(@Nullable final Project myProject, + @NotNull final OSProcessHandler processHandler, + @NotNull final ExecutionMode mode) { + final String title = mode.getTitle() != null ? mode.getTitle() : "Running. Please wait..."; + assert title != null; + + final Runnable process; + if (mode.cancelable()) { + process = createCancelableExecutionProcess(processHandler, mode.shouldCancelFun()); + } + else { + if (mode.getTimeout() <= 0) { + process = new Runnable() { + public void run() { + processHandler.waitFor(); + } + }; + } else { + process = createTimelimitedExecutionProcess(processHandler, mode.getTimeout()); + } + } + if (mode.withModalProgress()) { + ProgressManager.getInstance().runProcessWithProgressSynchronously(process, title, mode.cancelable(), myProject, + mode.getProgressParentComponent()); + } + else if (mode.inBackGround()) { + final Task task = new Task.Backgroundable(myProject, title, mode.cancelable()) { + public void run(@NotNull final ProgressIndicator indicator) { + process.run(); + } + }; + ProgressManager.getInstance().run(task); + } + else { + final String title2 = mode.getTitle2(); + final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + if (indicator != null && title2 != null) { + indicator.setText2(title2); + } + process.run(); + } + } + + private static Runnable createCancelableExecutionProcess(final ProcessHandler processHandler, + final Function cancelableFun) { + return new Runnable() { + private ProgressIndicator myProgressIndicator; + private final Semaphore mySemaphore = new Semaphore(); + + private final Runnable myWaitThread = new Runnable() { + public void run() { + try { + processHandler.waitFor(); + } + finally { + mySemaphore.up(); + } + } + }; + + private final Runnable myCancelListener = new Runnable() { + public void run() { + for (; ;) { + if ((myProgressIndicator != null && (myProgressIndicator.isCanceled() + || !myProgressIndicator.isRunning())) + || (cancelableFun != null && cancelableFun.fun(null).booleanValue()) + || processHandler.isProcessTerminated()) { + + if (!processHandler.isProcessTerminated()) { + try { + processHandler.destroyProcess(); + } + finally { + mySemaphore.up(); + } + } + break; + } + try { + synchronized (this) { + wait(1000); + } + } + catch (InterruptedException e) { + //Do nothing + } + } + } + }; + + public void run() { + myProgressIndicator = ProgressManager.getInstance().getProgressIndicator(); + if (myProgressIndicator != null && StringUtil.isEmpty(myProgressIndicator.getText())) { + myProgressIndicator.setText("Please wait"); + } + + LOG.assertTrue(myProgressIndicator != null || cancelableFun != null, + "Cancelable process must have an opportunity to be canceled!"); + mySemaphore.down(); + ApplicationManager.getApplication().executeOnPooledThread(myWaitThread); + ApplicationManager.getApplication().executeOnPooledThread(myCancelListener); + + mySemaphore.waitFor(); + } + }; + } + + private static Runnable createTimelimitedExecutionProcess(final OSProcessHandler processHandler, + final int timeout) { + return new Runnable() { + private final Semaphore mySemaphore = new Semaphore(); + private final Object LOCK = new Object(); + private Boolean processedFinished = Boolean.FALSE; + + private final Runnable myProcessThread = new Runnable() { + public void run() { + try { + processHandler.waitFor(); + synchronized (LOCK) { + processedFinished = Boolean.TRUE; + } + } + finally { + mySemaphore.up(); + } + } + }; + + private final Runnable myTimeoutListener = new Runnable() { + public void run() { + try { + synchronized (this) { + try { + wait(1000 * timeout); + synchronized (LOCK) { + if (!processedFinished) { + LOG.error("Timeout (" + timeout + " sec) on executing: " + processHandler.getCommandLine()); + processHandler.destroyProcess(); + } + } + } + finally { + mySemaphore.up(); + } + } + } + catch (InterruptedException e) { + //Do nothing + } + } + }; + + public void run() { + mySemaphore.down(); + ApplicationManager.getApplication().executeOnPooledThread(myProcessThread); + ApplicationManager.getApplication().executeOnPooledThread(myTimeoutListener); + + mySemaphore.waitFor(); + } + }; + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/execution/ExecutionMode.java b/platform/lang-impl/src/com/intellij/execution/ExecutionMode.java new file mode 100644 index 000000000000..81e8677fcac8 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/ExecutionMode.java @@ -0,0 +1,97 @@ +/* + * Copyright 2000-2010 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.execution; + +import com.intellij.util.Function; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** +* @author Roman.Chernyatchik +*/ +public abstract class ExecutionMode { + private final boolean myCancelable; + private final String myTitle; + private final String myTitle2; + private final boolean myRunWithModal; + private final boolean myRunInBG; + private final JComponent myProgressParentComponent; + private Function myShouldCancelFun; + private final Object CANCEL_FUN_LOCK = new Object(); + + public ExecutionMode(final boolean cancelable, + @Nullable final String title, + @Nullable final String title2, + final boolean runInBG, + final boolean runWithModal, + JComponent progressParentComponent) { + myCancelable = cancelable; + myTitle = title; + myTitle2 = title2; + myRunInBG = runInBG; + myRunWithModal = runWithModal; + myProgressParentComponent = progressParentComponent; + } + + public int getTimeout() { + // it is ignored + return -1; + } + + @Nullable + public String getTitle() { + return myTitle; + } + + @Nullable + public String getTitle2() { + return myTitle2; + } + + public boolean cancelable() { + return myCancelable; + } + + public boolean inBackGround() { + return myRunInBG; + } + + public boolean withModalProgress() { + return myRunWithModal; + } + + public JComponent getProgressParentComponent() { + return myProgressParentComponent; + } + + /** + * Runner checks this fun during process running, if returns true, process will be canceled. + */ + @Nullable + public Function shouldCancelFun() { + synchronized (CANCEL_FUN_LOCK) { + return myShouldCancelFun; + } + } + + public void setShouldCancelFun(final Function shouldCancelFun) { + synchronized (CANCEL_FUN_LOCK) { + myShouldCancelFun = shouldCancelFun; + } + } + +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/execution/ExecutionModes.java b/platform/lang-impl/src/com/intellij/execution/ExecutionModes.java new file mode 100644 index 000000000000..a03ac3ec6ef5 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/ExecutionModes.java @@ -0,0 +1,97 @@ +/* + * Copyright 2000-2010 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.execution; + +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * @author oleg + */ +public class ExecutionModes { + /** + * Process will be run in back ground mode + */ + public static class BackGroundMode extends ExecutionMode { + + public BackGroundMode(final boolean cancelable, @Nullable final String title) { + super(cancelable, title, null, true, false, null); + } + + public BackGroundMode(@Nullable final String title) { + this(true, title); + } + } + + /** + * Process will be run in modal dialog + */ + public static class ModalProgressMode extends ExecutionMode { + + public ModalProgressMode(final boolean cancelable, @Nullable final String title, JComponent progressParentComponent) { + super(cancelable, title, null, false, true, progressParentComponent); + } + + public ModalProgressMode(@Nullable final String title) { + this(true, title, null); + } + + public ModalProgressMode(@Nullable final String title, JComponent progressParentComponent) { + this(true, title, progressParentComponent); + } + } + + /** + * Process will be run in the same thread. + */ + public static class SameThreadMode extends ExecutionMode { + private final int myTimeout; + + public SameThreadMode(final boolean cancelable, + @Nullable final String title2, + final int timeout) { + super(cancelable, null, title2, false, false, null); + myTimeout = timeout; + } + + public SameThreadMode(@Nullable final String title2) { + this(true, title2, -1); + } + + /** + * @param cancelable + */ + public SameThreadMode(final boolean cancelable) { + this(cancelable, null, -1); + } + + /** + * @param timeout If less than zero it will be ignored + */ + public SameThreadMode(final int timeout) { + this(false, null, timeout); + } + + public SameThreadMode() { + this(true); + } + + public int getTimeout() { + return myTimeout; + } + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/Output.java b/platform/lang-impl/src/com/intellij/execution/Output.java new file mode 100644 index 000000000000..267046ce7464 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/Output.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2008 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.execution; + +/** + * Created by IntelliJ IDEA. + * + * @author: oleg + * @date: 24.08.2006 + */ +public class Output { + private final String stdout; + private final String stderr; + + public Output(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + } + + public String getStdout() { + return stdout; + } + + public String getStderr() { + return stderr; + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/OutputListener.java b/platform/lang-impl/src/com/intellij/execution/OutputListener.java new file mode 100644 index 000000000000..cba904e34f8e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/OutputListener.java @@ -0,0 +1,29 @@ +package com.intellij.execution; + +import com.intellij.execution.process.ProcessAdapter; +import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.process.ProcessOutputTypes; +import com.intellij.openapi.util.Key; +import org.jetbrains.annotations.NotNull; + +/** +* @author oleg +*/ +public class OutputListener extends ProcessAdapter { + private final StringBuilder out; + private final StringBuilder err; + + public OutputListener(@NotNull final StringBuilder out, @NotNull final StringBuilder err) { + this.out = out; + this.err = err; + } + + public void onTextAvailable(ProcessEvent event, Key outputType) { + if (outputType == ProcessOutputTypes.STDOUT) { + out.append(event.getText()); + } + if (outputType == ProcessOutputTypes.STDERR) { + err.append(event.getText()); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index 1bd9aa0360dc..60845b8dab93 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.execution.console; +import com.intellij.execution.process.ConsoleHighlighter; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.ide.DataManager; import com.intellij.ide.impl.TypeSafeDataProviderAdapter; @@ -22,6 +23,7 @@ import com.intellij.lang.Language; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.actions.EditorActionUtil; import com.intellij.openapi.editor.colors.EditorColors; @@ -199,7 +201,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { editorSettings.setAdditionalLinesCount(0); editorSettings.setAdditionalColumnsCount(1); editorSettings.setRightMarginShown(false); - editorSettings.setFoldingOutlineShown(false); + editorSettings.setFoldingOutlineShown(true); editorSettings.setLineNumbersShown(false); editorSettings.setLineMarkerAreaShown(false); editorSettings.setIndentGuidesShown(false); @@ -520,4 +522,17 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { } }); } + + public static void printToConsole(final LanguageConsoleImpl console, final String string, final ConsoleViewContentType type) { + printToConsole(console, string, type.getAttributes()); + } + + public static void printToConsole(final LanguageConsoleImpl console, final String string, final TextAttributes textAttributes) { + final TextAttributes attributes = TextAttributes.merge(ConsoleHighlighter.OUT.getDefaultAttributes(), textAttributes); + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + console.printToHistory(string, attributes); + } + }, ModalityState.stateForComponent(console.getComponent())); + } } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index b52e8a75bb2b..4666160d98d6 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -185,8 +185,8 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } }; - private final CompositeFilter myPredefinedMessageFilter; - private final CompositeFilter myCustomFilter; + protected final CompositeFilter myPredefinedMessageFilter; + protected final CompositeFilter myCustomFilter; private final ArrayList myHistory = new ArrayList(); private int myHistorySize = 20; @@ -196,7 +196,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo private final Alarm myFoldingAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, this); private final List myPendingFoldRegions = new ArrayList(); - public void addConsoleUserInputLestener(ConsoleInputListener consoleInputListener) { + public void addConsoleUserInputListener(ConsoleInputListener consoleInputListener) { myConsoleInputListeners.add(consoleInputListener); } @@ -500,10 +500,10 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo it.remove(); } } - highlightHyperlinks(newLineCount >= lineCount + 1 ? newLineCount - lineCount - 1 : 0, newLineCount - 1); + highlightHyperlinksAndFoldings(newLineCount >= lineCount + 1 ? newLineCount - lineCount - 1 : 0, newLineCount - 1); } else if (oldLineCount < newLineCount) { - highlightHyperlinks(oldLineCount - 1, newLineCount - 2); + highlightHyperlinksAndFoldings(oldLineCount - 1, newLineCount - 2); } if (isAtEndOfDocument) { @@ -574,11 +574,11 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo addHyperlink(textLength - hyperlinkText.length(), textLength, null, info, getHyperlinkAttributes()); } - private static TextAttributes getHyperlinkAttributes() { + public static TextAttributes getHyperlinkAttributes() { return EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.HYPERLINK_ATTRIBUTES); } - private static TextAttributes getFollowedHyperlinkAttributes() { + public static TextAttributes getFollowedHyperlinkAttributes() { return EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.FOLLOWED_HYPERLINK_ATTRIBUTES); } @@ -779,10 +779,13 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } } - private static final Key OLD_HYPERLINK_TEXT_ATTRIBUTES = Key.create("OLD_HYPERLINK_TEXT_ATTRIBUTES"); + public static final Key OLD_HYPERLINK_TEXT_ATTRIBUTES = Key.create("OLD_HYPERLINK_TEXT_ATTRIBUTES"); private void linkFollowed(final HyperlinkInfo info) { - MarkupModelEx markupModel = (MarkupModelEx)myEditor.getMarkupModel(); - for (Map.Entry entry : myHyperlinks.getRanges().entrySet()) { + linkFollowed(myEditor, myHyperlinks, info); + } + public static void linkFollowed(final Editor editor, final Hyperlinks hyperlinks, final HyperlinkInfo info) { + MarkupModelEx markupModel = (MarkupModelEx)editor.getMarkupModel(); + for (Map.Entry entry : hyperlinks.getRanges().entrySet()) { RangeHighlighter range = entry.getKey(); TextAttributes oldAttr = range.getUserData(OLD_HYPERLINK_TEXT_ATTRIBUTES); if (oldAttr != null) { @@ -805,29 +808,55 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo RangeHighlighter dummy = markupModel.addRangeHighlighter(0, 0, HYPERLINK_LAYER, getHyperlinkAttributes(), HighlighterTargetArea.EXACT_RANGE); markupModel.removeHighlighter(dummy); } + public HyperlinkInfo getHyperlinkInfoByPoint(final Point p){ + return getHyperlinkInfoByPoint(myEditor, myHyperlinks, p); + } - private HyperlinkInfo getHyperlinkInfoByPoint(final Point p){ - if (myEditor == null) return null; - final LogicalPosition pos = myEditor.xyToLogicalPosition(new Point(p.x, p.y)); - return getHyperlinkInfoByLineAndCol(pos.line, pos.column); + public static HyperlinkInfo getHyperlinkInfoByPoint(final Editor editor, final Hyperlinks hyperlinks, final Point p){ + final LogicalPosition pos = editor.xyToLogicalPosition(new Point(p.x, p.y)); + return getHyperlinkInfoByLineAndCol(editor, hyperlinks, pos.line, pos.column); } private HyperlinkInfo getHyperlinkInfoByLineAndCol(final int line, final int col) { - final int offset = myEditor.logicalPositionToOffset(new LogicalPosition(line, col)); - return myHyperlinks.getHyperlinkAt(offset); + return getHyperlinkInfoByLineAndCol(myEditor, myHyperlinks, line, col); } - private void highlightHyperlinks(final int line1, final int endLine){ + public static HyperlinkInfo getHyperlinkInfoByLineAndCol(final Editor editor, final Hyperlinks hyperlinks, final int line, final int col) { + final int offset = editor.logicalPositionToOffset(new LogicalPosition(line, col)); + return hyperlinks.getHyperlinkAt(offset); + } + + private void highlightHyperlinksAndFoldings(final int line1, final int endLine){ ApplicationManager.getApplication().assertIsDispatchThread(); PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + highlightHyperlinks(myEditor, myHyperlinks, myCustomFilter, myPredefinedMessageFilter, line1, endLine); + updateFoldings(line1, endLine); + } + + private void updateFoldings(final int line1, final int endLine) { final Document document = myEditor.getDocument(); final CharSequence chars = document.getCharsSequence(); + final int startLine = Math.max(0, line1); + final List toAdd = new ArrayList(); + for(int line = startLine; line <= endLine; line++) { + addFolding(document, chars, line, toAdd); + } + if (!toAdd.isEmpty()) { + doUpdateFolding(toAdd); + } + } + + public static void highlightHyperlinks(final Editor editor, + final Hyperlinks hyperlinks, + final Filter myCustomFilter, + final Filter myPredefinedMessageFilter, + final int line1, final int endLine){ + final Document document = editor.getDocument(); + final CharSequence chars = document.getCharsSequence(); final TextAttributes hyperlinkAttributes = getHyperlinkAttributes(); final int startLine = Math.max(0, line1); - final List toAdd = new ArrayList(); - for(int line = startLine; line <= endLine; line++) { int endOffset = document.getLineEndOffset(line); if (endOffset < document.getTextLength()) { @@ -842,12 +871,8 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo final int highlightStartOffset = result.highlightStartOffset; final int highlightEndOffset = result.highlightEndOffset; final HyperlinkInfo hyperlinkInfo = result.hyperlinkInfo; - addHyperlink(highlightStartOffset, highlightEndOffset, result.highlightAttributes, hyperlinkInfo, hyperlinkAttributes); + addHyperlink(editor, hyperlinks, highlightStartOffset, highlightEndOffset, result.highlightAttributes, hyperlinkInfo, hyperlinkAttributes); } - addFolding(document, chars, line, toAdd); - } - if (!toAdd.isEmpty()) { - doUpdateFolding(toAdd); } } @@ -907,7 +932,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } } - private static String getLineText(Document document, int lineNumber, boolean includeEol) { + public static String getLineText(Document document, int lineNumber, boolean includeEol) { int endOffset = document.getLineEndOffset(lineNumber); if (includeEol && endOffset < document.getTextLength()) { endOffset++; @@ -930,13 +955,22 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo final TextAttributes highlightAttributes, final HyperlinkInfo hyperlinkInfo, final TextAttributes hyperlinkAttributes) { + addHyperlink(myEditor, myHyperlinks, highlightStartOffset, highlightEndOffset, highlightAttributes, hyperlinkInfo, hyperlinkAttributes); + } + private static void addHyperlink(final Editor editor, + final Hyperlinks hyperlinks, + final int highlightStartOffset, + final int highlightEndOffset, + final TextAttributes highlightAttributes, + final HyperlinkInfo hyperlinkInfo, + final TextAttributes hyperlinkAttributes) { TextAttributes textAttributes = highlightAttributes != null ? highlightAttributes : hyperlinkAttributes; - final RangeHighlighter highlighter = myEditor.getMarkupModel().addRangeHighlighter(highlightStartOffset, + final RangeHighlighter highlighter = editor.getMarkupModel().addRangeHighlighter(highlightStartOffset, highlightEndOffset, HYPERLINK_LAYER, textAttributes, HighlighterTargetArea.EXACT_RANGE); - myHyperlinks.add(highlighter, hyperlinkInfo); + hyperlinks.add(highlighter, hyperlinkInfo); } private class ClearAllAction extends AnAction implements DumbAware { @@ -1201,7 +1235,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } } - private static class Hyperlinks { + public static class Hyperlinks { private static final int NO_INDEX = Integer.MIN_VALUE; private final Map myHighlighterToMessageInfoMap = new HashMap(); private int myLastIndex = NO_INDEX; @@ -1229,7 +1263,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo if (myLastIndex != NO_INDEX && containsOffset(myLastIndex, highlighter)) myLastIndex = NO_INDEX; } - private Map getRanges() { + public Map getRanges() { return myHighlighterToMessageInfoMap; } } diff --git a/platform/lang-impl/src/com/intellij/execution/rmi/RemoteProcessSupport.java b/platform/lang-impl/src/com/intellij/execution/rmi/RemoteProcessSupport.java new file mode 100644 index 000000000000..cd541b2a6cbe --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/rmi/RemoteProcessSupport.java @@ -0,0 +1,320 @@ +package com.intellij.execution.rmi; + +import com.intellij.execution.ExecutionException; +import com.intellij.execution.ExecutionResult; +import com.intellij.execution.Executor; +import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.configurations.RunProfileState; +import com.intellij.execution.executors.DefaultRunExecutor; +import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.process.ProcessListener; +import com.intellij.execution.process.ProcessOutputTypes; +import com.intellij.execution.runners.DefaultProgramRunner; +import com.intellij.execution.runners.ProgramRunner; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.ThrowableComputable; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.rmi.PortableRemoteObject; +import java.rmi.Remote; +import java.rmi.registry.LocateRegistry; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * @author Gregory.Shrago + */ +public abstract class RemoteProcessSupport { + private final Project myProject; + private final Class myValueClass; + private final HashMap, Object> myProcMap = + new HashMap, Object>(); + + public RemoteProcessSupport(Project project, Class valueClass) { + myProject = project; + myValueClass = valueClass; + } + + public Project getProject() { + return myProject; + } + + protected abstract void fireModificationCountChanged(); + + protected abstract String getName(Target target); + + protected void logText(Parameters configuration, ProcessEvent event, Key outputType, Object info) { + } + + + public void stopAll() { + final ArrayList allHandlers = new ArrayList(); + synchronized (myProcMap) { + for (Object o : myProcMap.values()) { + final ProcessHandler handler = o instanceof PendingInfo ? ((PendingInfo)o).handler : o instanceof Info ? ((Info)o).handler : null; + ContainerUtil.addIfNotNull(handler, allHandlers); + } + myProcMap.clear(); + } + for (ProcessHandler handler : allHandlers) { + handler.destroyProcess(); + } + } + + public List getActiveConfigurations(@NotNull Target target) { + final ArrayList result = new ArrayList(); + synchronized (myProcMap) { + for (Pair pair : myProcMap.keySet()) { + if (pair.first == target) { + result.add(pair.second); + } + } + } + return result; + } + + public EntryPoint acquire(@NotNull final Target target, @NotNull final Parameters configuration) throws Exception { + final Ref ref = Ref.create(null); + final Pair key = Pair.create(target, configuration); + if (!getExistingInfo(ref, key)) { + final Runnable runnable = new Runnable() { + public void run() { + startProcess(target, configuration, key); + } + }; + if (ApplicationManager.getApplication().isDispatchThread()) { + runnable.run(); + } + else { + ApplicationManager.getApplication().invokeLater(runnable); + } + if (ref.isNull()) { + try { + synchronized (ref) { + while (ref.isNull()) { + ref.wait(1000); + ProgressManager.checkCanceled(); + } + } + } + catch (InterruptedException e) { + ProgressManager.checkCanceled(); + } + } + } + if (ref.isNull()) throw new RuntimeException("Unable to acquire remote proxy for: " + getName(target)); + final Info info = ref.get(); + if (info.handler == null) throw new RuntimeException(info.name); + return acquire(info); + } + + public void release(@NotNull Target target, @Nullable Parameters configuration) { + final ArrayList handlersToStop = new ArrayList(); + final ArrayList> keysToRemove = new ArrayList>(); + synchronized (myProcMap) { + for (Pair pair : myProcMap.keySet()) { + if (pair.first == target && (configuration == null || pair.second == configuration)) { + final Object o = myProcMap.get(pair); + final ProcessHandler handler = o instanceof PendingInfo ? ((PendingInfo)o).handler : o instanceof Info ? ((Info)o).handler : null; + if (handler != null) { + handlersToStop.add(handler); + keysToRemove.add(pair); + } + else { + // todo what to do??? + } + } + } + myProcMap.keySet().removeAll(keysToRemove); + } + for (ProcessHandler handler : handlersToStop) { + handler.destroyProcess(); + } + fireModificationCountChanged(); + } + + private void startProcess(Target target, Parameters configuration, Pair key) { + final ProgramRunner runner = new DefaultProgramRunner() { + @NotNull + public String getRunnerId() { + return "MyRunner"; + } + + public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { + return true; + } + }; + try { + final Executor executor = DefaultRunExecutor.getRunExecutorInstance(); + final RunProfileState state = getRunProfileState(target, configuration, executor); + final ExecutionResult result = state.execute(executor, runner); + final ProcessHandler processHandler = result.getProcessHandler(); + processHandler.addProcessListener(getProcessListener(key)); + processHandler.startNotify(); + } + catch (ExecutionException e) { + handleProcessTerminated(key, e.getMessage()); + } + } + + protected abstract RunProfileState getRunProfileState(Target target, Parameters configuration, Executor executor) throws ExecutionException; + + private boolean getExistingInfo(Ref ref, final Pair key) { + Object info; + synchronized (myProcMap) { + info = myProcMap.get(key); + try { + while (info != null && + (!(info instanceof Info) || ((Info)info).handler.isProcessTerminating() || ((Info)info).handler.isProcessTerminated())) { + myProcMap.wait(1000); + ProgressManager.checkCanceled(); + info = myProcMap.get(key); + } + } + catch (InterruptedException e) { + ProgressManager.checkCanceled(); + } + if (info == null) { + myProcMap.put(key, new PendingInfo(ref, null)); + } + } + if (info != null) { + if (info instanceof Info) { + synchronized (ref) { + ref.set((Info)info); + ref.notifyAll(); + } + } + return true; + } + return false; + } + + private EntryPoint acquire(final Info port) throws Exception { + return RemoteUtil.executeWithClassLoader(new ThrowableComputable() { + public EntryPoint compute() throws Exception { + final Remote remote = LocateRegistry.getRegistry(port.port).lookup(port.name); + if (Remote.class.isAssignableFrom(myValueClass)) { + return RemoteUtil.substituteClassLoader(narrowImpl(remote, myValueClass), myValueClass.getClassLoader()); + } + else { + return RemoteUtil.castToLocal(remote, myValueClass); + } + } + }, myValueClass.getClassLoader()); + } + + private static T narrowImpl(Remote remote, Class to) { + return (T) (to.isInstance(remote)? remote : PortableRemoteObject.narrow(remote, to)); + } + + private ProcessListener getProcessListener(final Pair key) { + return new ProcessListener() { + public void startNotified(ProcessEvent event) { + final ProcessHandler processHandler = event.getProcessHandler(); + processHandler.putUserData(ProcessHandler.SILENTLY_DESTROY_ON_CLOSE, Boolean.TRUE); + final Object o; + synchronized (myProcMap) { + o = myProcMap.get(key); + if (o instanceof PendingInfo) { + myProcMap.put(key, new PendingInfo(((PendingInfo)o).ref, processHandler)); + } + } + } + + public void processTerminated(ProcessEvent event) { + handleProcessTerminated(key, null); + fireModificationCountChanged(); + } + + public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) { + } + + public void onTextAvailable(ProcessEvent event, Key outputType) { + Info result = null; + final PendingInfo info; + synchronized (myProcMap) { + final Object o = myProcMap.get(key); + logText(key.second, event, outputType, o); + if (o instanceof PendingInfo) { + info = (PendingInfo)o; + if (outputType == ProcessOutputTypes.STDOUT) { + final String text = event.getText(); + final String prefix = "Port/ID:"; + if (text != null && text.startsWith(prefix)) { + final String pair = text.substring(prefix.length()).trim(); + final int idx = pair.indexOf("/"); + result = new Info(info.handler, Integer.parseInt(pair.substring(0, idx)), pair.substring(idx + 1)); + myProcMap.put(key, result); + myProcMap.notifyAll(); + } + } + else if (outputType == ProcessOutputTypes.STDERR) { + info.stderr.append(event.getText()); + } + } + else info = null; + } + if (result != null) { + synchronized (info.ref) { + info.ref.set(result); + info.ref.notifyAll(); + } + fireModificationCountChanged(); + } + } + }; + } + + private void handleProcessTerminated(Pair key, String errorMessage) { + Object o; + final PendingInfo pendingInfo; + synchronized (myProcMap) { + o = myProcMap.remove(key); + pendingInfo = o instanceof PendingInfo? (PendingInfo)o : null; + if (pendingInfo != null && (pendingInfo.stderr.length() > 0 || pendingInfo.ref.isNull())) { + if (errorMessage != null) pendingInfo.stderr.append(errorMessage); + pendingInfo.ref.set(new Info(null, -1, pendingInfo.stderr.toString())); + } + myProcMap.notifyAll(); + } + if (pendingInfo != null) { + synchronized (pendingInfo.ref) { + pendingInfo.ref.notifyAll(); + } + } + } + + private static class PendingInfo { + final Ref ref; + final ProcessHandler handler; + final StringBuilder stderr = new StringBuilder(); + + private PendingInfo(Ref ref, ProcessHandler handler) { + this.ref = ref; + this.handler = handler; + } + } + + private static class Info { + final ProcessHandler handler; + final int port; + final String name; + + private Info(ProcessHandler handler, int port, String name) { + this.handler = handler; + this.port = port; + this.name = name; + } + } + +} diff --git a/platform/lang-impl/src/com/intellij/execution/rmi/RemoteUtil.java b/platform/lang-impl/src/com/intellij/execution/rmi/RemoteUtil.java new file mode 100644 index 000000000000..2ab1c3f25082 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/rmi/RemoteUtil.java @@ -0,0 +1,144 @@ +package com.intellij.execution.rmi; + +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.ThrowableComputable; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ConcurrentFactoryMap; +import gnu.trove.THashMap; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.rmi.Remote; +import java.util.Map; + +/** + * @author Gregory.Shrago + */ + public class RemoteUtil { + RemoteUtil() { + } + + private static final ConcurrentFactoryMap, Class>, Map> ourRemoteToLocalMap = new ConcurrentFactoryMap,Class>, Map>() { + @Override + protected Map create(Pair, Class> key) { + final THashMap map = new THashMap(); + for (Method method : key.second.getMethods()) { + Method m = null; + main: + for (Method candidate : key.first.getMethods()) { + if (!candidate.getName().equals(method.getName())) continue; + Class[] cpts = candidate.getParameterTypes(); + Class[] mpts = method.getParameterTypes(); + if (cpts.length != mpts.length) continue; + for (int i = 0; i < mpts.length; i++) { + Class mpt = mpts[i]; + Class cpt = cpts[i]; + if (!cpt.isAssignableFrom(mpt)) continue main; + } + m = candidate; + break; + } + if (m != null) map.put(method, m); + } + return map; + } + }; + + public static T castToLocal(final Object remote, final Class jdbcClass) { + final ClassLoader loader = jdbcClass.getClassLoader(); + Object proxy = Proxy.newProxyInstance(loader, new Class[]{jdbcClass}, new InvocationHandler() { + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (method.getDeclaringClass() == Object.class) { + return method.invoke(remote, args); + } + else { + Method m = ourRemoteToLocalMap.get(Pair., Class>create(remote.getClass(), jdbcClass)).get(method); + if (m == null) throw new NoSuchMethodError(method.getName() + " in " + remote.getClass()); + try { + Object result = m.invoke(remote, args); + if (result instanceof Remote) { + return castToLocal(result, tryFixReturnType(result, method.getReturnType(), loader)); + } + return result; + } + catch (InvocationTargetException e) { + Throwable cause = e; + for (; cause.getCause() != null; cause = cause.getCause()); + if (cause instanceof RuntimeException) throw cause; + if (ArrayUtil.indexOf(method.getExceptionTypes(), cause.getClass()) > -1) throw cause; + throw new RuntimeException(cause); + } + catch (RuntimeException e) { + throw e; + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + } + }); + return (T)proxy; + } + + private static Class tryFixReturnType(Object result, Class returnType, ClassLoader loader) throws Exception { + if (returnType.isInterface()) return returnType; + if (result instanceof RemoteCastable) { + final String className = ((RemoteCastable)result).getCastToClassName(); + return Class.forName(className, true, loader); + } + return returnType; + } + + public static T substituteClassLoader(final T remote, final ClassLoader classLoader) throws Exception { + return executeWithClassLoader(new ThrowableComputable() { + public T compute() { + Object proxy = Proxy.newProxyInstance(classLoader, remote.getClass().getInterfaces(), new InvocationHandler() { + public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable { + return executeWithClassLoader(new ThrowableComputable() { + public Object compute() throws Exception { + try { + final Object result = method.invoke(remote, args); + if (result instanceof Remote) { + if (result instanceof RemoteCastable) { + return castToLocal(result, tryFixReturnType(result, method.getReturnType(), classLoader)); + } + return substituteClassLoader(result, classLoader); + } + return result; + } + catch (InvocationTargetException e) { + Throwable cause = e; + while (cause.getCause() != null) cause = cause.getCause(); + if (cause instanceof RuntimeException) throw (RuntimeException)cause; + if (cause instanceof Exception && ArrayUtil.indexOf(method.getExceptionTypes(), cause.getClass()) > -1) throw (Exception)cause; + throw new RuntimeException(cause); + } + catch (RuntimeException e) { + throw e; + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + }, classLoader); + } + }); + return (T)proxy; + } + }, classLoader); + } + + public static T executeWithClassLoader(final ThrowableComputable action, final ClassLoader classLoader) throws Exception { + final Thread thread = Thread.currentThread(); + final ClassLoader prev = thread.getContextClassLoader(); + try { + thread.setContextClassLoader(classLoader); + return action.compute(); + } + finally { + thread.setContextClassLoader(prev); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/runners/AbstractConsoleRunnerWithHistory.java b/platform/lang-impl/src/com/intellij/execution/runners/AbstractConsoleRunnerWithHistory.java new file mode 100644 index 000000000000..47c217b0e4eb --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/runners/AbstractConsoleRunnerWithHistory.java @@ -0,0 +1,270 @@ +/* + * Copyright 2000-2010 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.execution.runners; + +import com.intellij.codeInsight.lookup.Lookup; +import com.intellij.codeInsight.lookup.LookupManager; +import com.intellij.execution.ExecutionException; +import com.intellij.execution.ExecutionManager; +import com.intellij.execution.Executor; +import com.intellij.execution.ExecutorRegistry; +import com.intellij.execution.console.LanguageConsoleImpl; +import com.intellij.execution.console.LanguageConsoleViewImpl; +import com.intellij.execution.executors.DefaultRunExecutor; +import com.intellij.execution.process.*; +import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.execution.ui.actions.CloseAction; +import com.intellij.ide.CommonActionsManager; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.util.PairProcessor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.ArrayList; + +/** + * @author oleg + * This class provides basic functionality for running consoles. + * It launches extrnal process and handles line input with history + */ +public abstract class AbstractConsoleRunnerWithHistory { + protected final Project myProject; + protected final String myConsoleTitle; + + protected OSProcessHandler myProcessHandler; + protected final CommandLineArgumentsProvider myProvider; + protected final String myWorkingDir; + + protected LanguageConsoleViewImpl myConsoleView; + private final ConsoleHistoryModel myHistory = new ConsoleHistoryModel(); + private AnAction myRunAction; + + public AbstractConsoleRunnerWithHistory(@NotNull final Project project, + @NotNull final String consoleTitle, + @NotNull final CommandLineArgumentsProvider provider, + @Nullable final String workingDir) { + myProject = project; + myConsoleTitle = consoleTitle; + myProvider = provider; + myWorkingDir = workingDir; + } + + /** + * Launch process, setup history, actions etc. + * @throws ExecutionException + */ + public void initAndRun() throws ExecutionException { + // Create Server process + final Process process = createProcess(); + + // Init console view + myConsoleView = createConsoleView(); + + myProcessHandler = createProcessHandler(process); + + ProcessTerminatedListener.attach(myProcessHandler); + + myProcessHandler.addProcessListener(new ProcessAdapter() { + @Override + public void processTerminated(ProcessEvent event) { + myRunAction.getTemplatePresentation().setEnabled(false); + myConsoleView.getConsole().setPrompt(""); + myConsoleView.getConsole().getConsoleEditor().setRendererMode(true); + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + myConsoleView.getConsole().getConsoleEditor().getComponent().updateUI(); + } + }); + } + }); + +// Attach to process + myConsoleView.attachToProcess(myProcessHandler); + +// Runner creating + final Executor defaultExecutor = ExecutorRegistry.getInstance().getExecutorById(DefaultRunExecutor.EXECUTOR_ID); + final DefaultActionGroup toolbarActions = new DefaultActionGroup(); + final ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, toolbarActions, false); + +// Runner creating + final JPanel panel = new JPanel(new BorderLayout()); + panel.add(actionToolbar.getComponent(), BorderLayout.WEST); + panel.add(myConsoleView.getComponent(), BorderLayout.CENTER); + + final RunContentDescriptor myDescriptor = + new RunContentDescriptor(myConsoleView, myProcessHandler, panel, myConsoleTitle); + +// tool bar actions + final AnAction[] actions = fillToolBarActions(toolbarActions, defaultExecutor, myDescriptor); + registerActionShortcuts(actions, getLanguageConsole().getConsoleEditor().getComponent()); + registerActionShortcuts(actions, panel); + panel.updateUI(); + +// Show in run toolwindow + ExecutionManager.getInstance(myProject).getContentManager().showRunContent(defaultExecutor, myDescriptor); + +// Request focus + final ToolWindow window = ToolWindowManager.getInstance(myProject).getToolWindow(defaultExecutor.getId()); + window.activate(new Runnable() { + public void run() { + IdeFocusManager.getInstance(myProject).requestFocus(getLanguageConsole().getCurrentEditor().getContentComponent(), true); + } + }); +// Run + myProcessHandler.startNotify(); + } + + protected abstract LanguageConsoleViewImpl createConsoleView(); + + @Nullable + protected abstract Process createProcess() throws ExecutionException; + + protected abstract OSProcessHandler createProcessHandler(final Process process); + + private void registerActionShortcuts(final AnAction[] actions, final JComponent component) { + for (AnAction action : actions) { + if (action.getShortcutSet() != null) { + action.registerCustomShortcutSet(action.getShortcutSet(), component); + } + } + } + + protected AnAction[] fillToolBarActions(final DefaultActionGroup toolbarActions, + final Executor defaultExecutor, + final RunContentDescriptor myDescriptor) { +//stop + final AnAction stopAction = createStopAction(); + toolbarActions.add(stopAction); + +//close + final AnAction closeAction = createCloseAction(defaultExecutor, myDescriptor); + toolbarActions.add(closeAction); + +// run action + myRunAction = new DumbAwareAction(null, null, IconLoader.getIcon("/actions/execute.png")) { + public void actionPerformed(final AnActionEvent e) { + runExecuteActionInner(); + } + + public void update(final AnActionEvent e) { + final EditorEx editor = getLanguageConsole().getConsoleEditor(); + final Lookup lookup = LookupManager.getActiveLookup(editor); + e.getPresentation().setEnabled(!myProcessHandler.isProcessTerminated() && + (lookup == null || !lookup.isCompletion())); + } + }; + EmptyAction.setupAction(myRunAction, "Console.Execute", null); + toolbarActions.add(myRunAction); + +// Help + toolbarActions.add(CommonActionsManager.getInstance().createHelpAction("interactive_console")); + +// history actions + final PairProcessor historyProcessor = new PairProcessor() { + public boolean process(final AnActionEvent e, final String s) { + new WriteCommandAction(myProject, getLanguageConsole().getFile()) { + protected void run(final Result result) throws Throwable { + getLanguageConsole().getEditorDocument().setText(s == null? "" : s); + } + }.execute(); + return true; + } + }; + final AnAction historyNextAction = ConsoleHistoryModel.createHistoryAction(myHistory, true, historyProcessor); + final AnAction historyPrevAction = ConsoleHistoryModel.createHistoryAction(myHistory, false, historyProcessor); + historyNextAction.getTemplatePresentation().setVisible(false); + historyPrevAction.getTemplatePresentation().setVisible(false); + toolbarActions.add(historyNextAction); + toolbarActions.add(historyPrevAction); + + return new AnAction[]{stopAction, closeAction, myRunAction, historyNextAction, historyPrevAction}; + } + + protected AnAction createCloseAction(final Executor defaultExecutor, final RunContentDescriptor myDescriptor) { + return new CloseAction(defaultExecutor, myDescriptor, myProject); + } + + protected AnAction createStopAction() { + return ActionManager.getInstance().getAction(IdeActions.ACTION_STOP_PROGRAM); + } + + public void sendInput(final String input) { + final Charset charset = myProcessHandler.getCharset(); + final OutputStream outputStream = myProcessHandler.getProcessInput(); + try { + byte[] bytes = input.getBytes(charset.name()); + outputStream.write(bytes); + outputStream.flush(); + } + catch (IOException e) { + // ignore + } + } + + public LanguageConsoleImpl getLanguageConsole() { + return myConsoleView.getConsole(); + } + + protected void runExecuteActionInner() { + // Process input and add to history + final Document document = getLanguageConsole().getCurrentEditor().getDocument(); + final String documentText = document.getText(); + final TextRange range = new TextRange(0, document.getTextLength()); + getLanguageConsole().getCurrentEditor().getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset()); + getLanguageConsole().addCurrentToHistory(range, false); + getLanguageConsole().setInputText(""); + final String line = documentText; + if (!StringUtil.isEmptyOrSpaces(line)){ + myHistory.addToHistory(line); + } + // Send to interpreter / server + final String text2send = line.length() == 0 ? "\n\n" : line + "\n"; + sendInput(text2send); + } + + protected static String getProviderCommandLine(final CommandLineArgumentsProvider provider) { + final StringBuilder builder = new StringBuilder(); + for (String s : provider.getArguments()) { + if (builder.length() > 0){ + builder.append(' '); + } + builder.append(s); + } + return builder.toString(); + } + + public Project getProject() { + return myProject; + } +} diff --git a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java index 64110e91224d..f1a3c0e08dcf 100644 --- a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java +++ b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java @@ -54,10 +54,7 @@ import com.intellij.ui.TableScrollingUtil; import com.intellij.ui.awt.RelativePoint; import com.intellij.usageView.UsageViewBundle; import com.intellij.usages.*; -import com.intellij.usages.impl.GroupNode; -import com.intellij.usages.impl.NullUsage; -import com.intellij.usages.impl.UsageNode; -import com.intellij.usages.impl.UsageViewImpl; +import com.intellij.usages.impl.*; import com.intellij.usages.rules.UsageFilteringRuleProvider; import com.intellij.util.ArrayUtil; import com.intellij.util.Icons; @@ -110,12 +107,26 @@ public class ShowUsagesAction extends AnAction { hideHints(); } }; + private final UsageViewSettings myUsageViewSettings; // used from plugin.xml @SuppressWarnings({"UnusedDeclaration"}) public ShowUsagesAction() { + this(false); + } + + private ShowUsagesAction(boolean showDialogBefore) { setInjectedContext(true); - showSettingsDialogBefore = false; + showSettingsDialogBefore = showDialogBefore; + + final UsageViewSettings usageViewSettings = UsageViewSettings.getInstance(); + myUsageViewSettings = new UsageViewSettings(); + myUsageViewSettings.loadState(usageViewSettings); + myUsageViewSettings.GROUP_BY_FILE_STRUCTURE = false; + myUsageViewSettings.GROUP_BY_MODULE = false; + myUsageViewSettings.GROUP_BY_PACKAGE = false; + myUsageViewSettings.GROUP_BY_USAGE_TYPE = false; + myUsageViewSettings.GROUP_BY_SCOPE = false; } public static class ShowSettings extends ShowUsagesAction { @@ -124,11 +135,6 @@ public class ShowUsagesAction extends AnAction { } } - private ShowUsagesAction(boolean showDialogBefore) { - setInjectedContext(true); - showSettingsDialogBefore = showDialogBefore; - } - public void actionPerformed(AnActionEvent e) { final Project project = e.getData(PlatformDataKeys.PROJECT); if (project == null) return; @@ -177,25 +183,18 @@ public class ShowUsagesAction extends AnAction { presentation.setDetachedMode(true); final UsageViewSettings usageViewSettings = UsageViewSettings.getInstance(); - final UsageViewSettings save = new UsageViewSettings(); + final UsageViewSettings savedGlobalSettings = new UsageViewSettings(); - save.loadState(usageViewSettings); - usageViewSettings.GROUP_BY_FILE_STRUCTURE = false; - usageViewSettings.GROUP_BY_MODULE = false; - usageViewSettings.GROUP_BY_PACKAGE = false; - usageViewSettings.GROUP_BY_USAGE_TYPE = false; - usageViewSettings.GROUP_BY_SCOPE = false; + savedGlobalSettings.loadState(usageViewSettings); + usageViewSettings.loadState(myUsageViewSettings); UsageViewManager manager = UsageViewManager.getInstance(handler.getProject()); final UsageViewImpl usageView = (UsageViewImpl)manager.createUsageView(UsageTarget.EMPTY_ARRAY, Usage.EMPTY_ARRAY, presentation, null); Disposer.register(usageView, new Disposable() { public void dispose() { - usageViewSettings.GROUP_BY_FILE_STRUCTURE = save.GROUP_BY_FILE_STRUCTURE; - usageViewSettings.GROUP_BY_MODULE = save.GROUP_BY_MODULE; - usageViewSettings.GROUP_BY_PACKAGE = save.GROUP_BY_PACKAGE; - usageViewSettings.GROUP_BY_USAGE_TYPE = save.GROUP_BY_USAGE_TYPE; - usageViewSettings.GROUP_BY_SCOPE = save.GROUP_BY_SCOPE; + myUsageViewSettings.loadState(usageViewSettings); + usageViewSettings.loadState(savedGlobalSettings); } }); @@ -431,10 +430,11 @@ public class ShowUsagesAction extends AnAction { }); builder.setCommandButton(button); - DefaultActionGroup filters = new DefaultActionGroup(); - usageView.addFilteringActions(filters); + DefaultActionGroup toolbar = new DefaultActionGroup(); + usageView.addFilteringActions(toolbar); - filters.add(new AnAction("Open Find Usages Toolwindow", "Show all usages in a separate toolwindow", IconLoader.getIcon("/general/toolWindowFind.png")) { + toolbar.add(UsageGroupingRuleProviderImpl.createGroupByFileStructureAction(usageView)); + toolbar.add(new AnAction("Open Find Usages Toolwindow", "Show all usages in a separate toolwindow", IconLoader.getIcon("/general/toolWindowFind.png")) { { AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_FIND_USAGES); setShortcutSet(action.getShortcutSet()); @@ -453,14 +453,14 @@ public class ShowUsagesAction extends AnAction { } }); - ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.USAGE_VIEW_TOOLBAR, filters, true); + ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.USAGE_VIEW_TOOLBAR, toolbar, true); actionToolbar.setReservePlaceAutoPopupIcon(false); final JComponent toolBar = actionToolbar.getComponent(); toolBar.setOpaque(false); builder.setSettingButton(toolBar); popup[0] = builder.createPopup(); - for (AnAction action : filters.getChildren(null)) { + for (AnAction action : toolbar.getChildren(null)) { action.unregisterCustomShortcutSet(usageView.getComponent()); action.registerCustomShortcutSet(action.getShortcutSet(), popup[0].getContent()); } diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetAdapter.java b/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetAdapter.java index 12c384bc4a29..8e2fa77fb07b 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetAdapter.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetAdapter.java @@ -120,7 +120,7 @@ public class PsiElement2UsageTargetAdapter implements PsiElementUsageTarget, Typ final FindUsagesHandler handler = findUsagesManager.getFindUsagesHandler(target, true); Collection refs; - // in case of injected file, use host file to highlight all occurences of the target in each injected file + // in case of injected file, use host file to highlight all occurrences of the target in each injected file PsiFile context = InjectedLanguageUtil.getTopLevelFile(file); SearchScope searchScope = new LocalSearchScope(context); if (handler != null) { diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java index 40d6b71065cb..de1142c26a7d 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java @@ -942,6 +942,7 @@ class FindDialog extends DialogWrapper { model.setModuleName(null); model.setCustomScopeName(null); model.setCustomScope(null); + model.setCustomScope(false); if (myRbDirectory.isSelected()) { String directory = getDirectory(); @@ -957,6 +958,7 @@ class FindDialog extends DialogWrapper { String customScopeName = selectedScope == null ? null : selectedScope.getDisplayName(); model.setCustomScopeName(customScopeName); model.setCustomScope(selectedScope == null ? null : selectedScope); + model.setCustomScope(true); findSettings.setCustomScope(customScopeName); } } @@ -983,8 +985,17 @@ class FindDialog extends DialogWrapper { } } } + if (myModel.isCustomScope()) { + myRbCustomScope.setSelected(true); - if (myModel.isProjectScope()) { + myScopeCombo.setEnabled(true); + myScopeCombo.init(myProject, true, true, myModel.getCustomScopeName()); + + myCbWithSubdirectories.setEnabled(false); + myDirectoryComboBox.setEnabled(false); + mySelectDirectoryButton.setEnabled(false); + myModuleComboBox.setEnabled(false); + } else if (myModel.isProjectScope()) { myRbProject.setSelected(true); myCbWithSubdirectories.setEnabled(false); @@ -1015,17 +1026,6 @@ class FindDialog extends DialogWrapper { myRbModule.setVisible(true); myModuleComboBox.setVisible(true); } - else if (myModel.getCustomScopeName() != null) { - myRbCustomScope.setSelected(true); - - myScopeCombo.setEnabled(true); - myScopeCombo.init(myProject, true, true, myModel.getCustomScopeName()); - - myCbWithSubdirectories.setEnabled(false); - myDirectoryComboBox.setEnabled(false); - mySelectDirectoryButton.setEnabled(false); - myModuleComboBox.setEnabled(false); - } else { assert false; } diff --git a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java index 4a6afb5f9c23..6b3bddec876c 100644 --- a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java @@ -200,7 +200,12 @@ public abstract class AbstractBlockWrapper { return childIndent.add(myParent.getChildOffset(this, options, tokenBlockStartOffset)); } } else if (!getWhiteSpace().containsLineFeeds()) { - return childIndent.add(myParent.getChildOffset(this, options, tokenBlockStartOffset)); + if (isIndentAffectedAlignment(child)) { + return createAlignmentIndent(childIndent, child); + } + else { + return childIndent.add(myParent.getChildOffset(this, options, tokenBlockStartOffset)); + } } else { if (myParent == null) return childIndent.add(getWhiteSpace()); if (getIndent().isAbsolute()) { @@ -212,7 +217,12 @@ public abstract class AbstractBlockWrapper { } } if ((myFlags & CAN_USE_FIRST_CHILD_INDENT_AS_BLOCK_INDENT) != 0) { - return childIndent.add(getWhiteSpace()); + if (isIndentAffectedAlignment(child)) { + return createAlignmentIndent(childIndent, child); + } + else { + return childIndent.add(getWhiteSpace()); + } } else { return childIndent.add(myParent.getChildOffset(this, options, tokenBlockStartOffset)); @@ -229,6 +239,21 @@ public abstract class AbstractBlockWrapper { */ protected abstract boolean indentAlreadyUsedBefore(final AbstractBlockWrapper child); + /** + * Allows to retrieve object that encapsulates information about number of symbols before the current block starting + * from the line start. I.e. all symbols (either white space or not) between start of the line where current block begins + * and the block itself are count and returned. + * + * @return object that encapsulates information about number of symbols before the current block + */ + protected abstract IndentData getNumberOfSymbolsBeforeBlock(); + + /** + * @return previous block for the current block if any; null otherwise + */ + @Nullable + protected abstract AbstractBlockWrapper getPreviousBlock(); + protected final void setCanUseFirstChildIndentAsBlockIndent(final boolean newValue) { if (newValue) myFlags |= CAN_USE_FIRST_CHILD_INDENT_AS_BLOCK_INDENT; else myFlags &= ~CAN_USE_FIRST_CHILD_INDENT_AS_BLOCK_INDENT; @@ -261,6 +286,89 @@ public abstract class AbstractBlockWrapper { } + /** + * Allows to answer if indent for the given child block should be calculated + * + * @param child + * @return + */ + private boolean isIndentAffectedAlignment(AbstractBlockWrapper child) { + if (!child.getWhiteSpace().containsLineFeeds()) { + return false; + } + AlignmentImpl alignment = getAlignmentAtStartOffset(); + if (alignment == null || alignment == child.getAlignment()) { + return false; + } + + LeafBlockWrapper anchorOffsetBlock = alignment.getOffsetRespBlockBefore(child); + return anchorOffsetBlock == null || anchorOffsetBlock.getStartOffset() >= getStartOffset(); + } + + /** + * Allows to retrieve alignment applied to any block that conforms to the following conditions: + *

+ *

    + *
  • that block is current block or its ancestor (direct or indirect parent);
  • + *
  • that block starts at the same offset as the current one;
  • + *
+ * + * @return alignment of the current block or it's ancestor that starts at the same offset as the current if any; + * null otherwise + */ + @Nullable + private AlignmentImpl getAlignmentAtStartOffset() { + for (AbstractBlockWrapper block = this; block != null && block.getStartOffset() == getStartOffset(); block = block.getParent()) { + if (block.getAlignment() != null) { + return block.getAlignment(); + } + } + return null; + } + + /** + * Allows to construct indent for the block that is affected by aligning rules. E.g. there is a possible case that the user + * configures method call arguments to be aligned and single parameter expression spans more than one line: + *

+ *

+   *     public void test(String s1, String s2) {}
+   *
+   *     public void foo() {
+   *         test("11"
+   *                  + "12"
+   *                  + "13",
+   *              "21"
+   *                  + "22");
+   *     }
+   * 
+ *

+ * Here both composite blocks ("11" + "12" + "13" and "21" + "22") are aligned as method call argument but their + * sub-blocks that are located on new lines should also be indented to the point of composite block start. + *

+ * This method takes care about constructing target absolute indent of the given child block assuming that it's parent + * (referenced by 'this') or it's ancestor that starts at the same offset is aligned. I.e. it assumes + * that {@link #isIndentAffectedAlignment(AbstractBlockWrapper)} returns true for the given child block. + * + * @param indentFromParent basic indent of given child from the current parent block + * @param child child block of the current aligned composite block + * @return absolute indent to use for the given child block of the current composite block + */ + private IndentData createAlignmentIndent(IndentData indentFromParent, AbstractBlockWrapper child) { + AbstractBlockWrapper previous = child.getPreviousBlock(); + + // There is no point in continuing processing if given child is the first block, i.e. there is no alignment-implied + // offset to add to the given 'indent from parent'. + if (previous == null) { + return indentFromParent; + } + + IndentData symbolsBeforeCurrent = getNumberOfSymbolsBeforeBlock(); + + // Result is calculated as a number of symbols between the current composite parent block plus given 'indent from parent'. + int indentSpaces = symbolsBeforeCurrent.getIndentSpaces() + indentFromParent.getSpaces() + indentFromParent.getIndentSpaces(); + return new IndentData(indentSpaces, symbolsBeforeCurrent.getSpaces()); + } + private static IndentData getIndent(final CodeStyleSettings.IndentOptions options, final int index, IndentImpl indent) { if (indent.getType() == IndentImpl.Type.CONTINUATION) { return new IndentData(options.CONTINUATION_INDENT_SIZE); diff --git a/platform/lang-impl/src/com/intellij/formatting/AlignmentImpl.java b/platform/lang-impl/src/com/intellij/formatting/AlignmentImpl.java index 0171c1336ea9..0d98a10e543c 100644 --- a/platform/lang-impl/src/com/intellij/formatting/AlignmentImpl.java +++ b/platform/lang-impl/src/com/intellij/formatting/AlignmentImpl.java @@ -16,14 +16,13 @@ package com.intellij.formatting; +import org.jetbrains.annotations.Nullable; + import java.util.*; class AlignmentImpl extends Alignment { private static final List EMPTY = Collections.unmodifiableList(new ArrayList(0)); private Collection myOffsetRespBlocks = EMPTY; - private final int myFlags; - private static int ourId = 0; - private static final int ID_SHIFT = 1; private AlignmentImpl myParentAlignment; public String getId() { @@ -38,18 +37,6 @@ class AlignmentImpl extends Alignment { myParentAlignment = (AlignmentImpl)base; } - static enum Type{ - FULL,NORMAL - } - - public AlignmentImpl(final Type type) { - myFlags = ((ourId++) >> ID_SHIFT) | type.ordinal(); - } - - final Type getType() { - return Type.values()[myFlags & 1]; - } - /** * Selects target wrapped block by the following algorithm: *

    @@ -82,7 +69,8 @@ class AlignmentImpl extends Alignment { * @return block {@link #setOffsetRespBlock(LeafBlockWrapper) registered} for the current alignment object or * {@link #setParent(Alignment) its parent} using the algorithm above if any; null otherwise */ - LeafBlockWrapper getOffsetRespBlockBefore(final LeafBlockWrapper block) { + @Nullable + LeafBlockWrapper getOffsetRespBlockBefore(final AbstractBlockWrapper block) { LeafBlockWrapper result = null; if (myOffsetRespBlocks != EMPTY) { LeafBlockWrapper lastBlockAfterLineFeed = null; @@ -116,20 +104,20 @@ class AlignmentImpl extends Alignment { result = lastAlignedBlock; } } + if (result == null && myParentAlignment != null) { return myParentAlignment.getOffsetRespBlockBefore(block); } else { return result; } - } /** * Registers wrapped block within the current alignment in order to use it for further - * {@link #getOffsetRespBlockBefore(LeafBlockWrapper)} calls processing. + * {@link #getOffsetRespBlockBefore(AbstractBlockWrapper)} calls processing. * - * @param block wrapped block to register within the curretn alignmnent object + * @param block wrapped block to register within the current alignment object */ void setOffsetRespBlock(final LeafBlockWrapper block) { if (myOffsetRespBlocks == EMPTY) myOffsetRespBlocks = new LinkedHashSet(1); diff --git a/platform/lang-impl/src/com/intellij/formatting/BlockDebugUtil.java b/platform/lang-impl/src/com/intellij/formatting/BlockDebugUtil.java index fc39a126d0a6..f76e2eb14be1 100644 --- a/platform/lang-impl/src/com/intellij/formatting/BlockDebugUtil.java +++ b/platform/lang-impl/src/com/intellij/formatting/BlockDebugUtil.java @@ -36,11 +36,21 @@ public class BlockDebugUtil { */ public static void dumpBlockTree(PrintStream out, Block block) { out.println("--- BLOCK TREE DUMP ---"); - dumpBlockTree(out, block, ""); + dumpBlockTree(out, block, "", true); out.println("--- END OF DUMP ---\n\n"); } - private static void dumpBlockTree(PrintStream out, Block block, String indent) { + + /** + * Print out a single block info without child blocks. + * @param out The output stream. + * @param block The block to print the info for. + */ + public static void dumpBlock(PrintStream out, Block block) { + dumpBlockTree(out, block, "", false); + } + + private static void dumpBlockTree(PrintStream out, Block block, String indent, boolean withChildren) { if (block == null) return; out.print(indent + block.getClass().getSimpleName()); if (block.getIndent() != null) { @@ -49,6 +59,7 @@ public class BlockDebugUtil { else { out.print(" "); } + out.print(" " + block.getTextRange() + " "); if (block instanceof ASTBlock) { ASTNode node = ((ASTBlock)block).getNode(); if (node != null) { @@ -61,20 +72,20 @@ public class BlockDebugUtil { out.print(" \"" + text + "\""); } } - System.out.println(); - List subBlocks = getSubBlocks(block); - if (subBlocks != null && subBlocks.size() > 0) { - out.println(indent + "{"); - for (Block child : subBlocks) { - dumpBlockTree(out, child, indent + " "); + out.println(); + if (withChildren) { + List subBlocks = getSubBlocks(block); + if (subBlocks != null && subBlocks.size() > 0) { + out.println(indent + "{"); + for (Block child : subBlocks) { + dumpBlockTree(out, child, indent + " ", true); + } + out.println(indent + "}"); } - out.println(indent + "}"); } } private static List getSubBlocks(Block root) { - if (root instanceof AbstractBlock) return ((AbstractBlock)root).getSubBlocks(); - if (root instanceof DataLanguageBlockWrapper) return ((DataLanguageBlockWrapper)root).getSubBlocks(); - return null; + return root.getSubBlocks(); } } diff --git a/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java index 84959f84dc2e..805bbf49aff0 100644 --- a/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java @@ -57,6 +57,7 @@ public class CompositeBlockWrapper extends AbstractBlockWrapper{ } } + @Override protected boolean indentAlreadyUsedBefore(final AbstractBlockWrapper child) { for (AbstractBlockWrapper childBefore : myChildren) { if (childBefore == child) return false; @@ -65,6 +66,22 @@ public class CompositeBlockWrapper extends AbstractBlockWrapper{ return false; } + @Override + protected IndentData getNumberOfSymbolsBeforeBlock() { + if (myChildren == null || myChildren.isEmpty()) { + return new IndentData(0, 0); + } + return myChildren.get(0).getNumberOfSymbolsBeforeBlock(); + } + + @Override + protected AbstractBlockWrapper getPreviousBlock() { + if (myChildren == null || myChildren.isEmpty()) { + return null; + } + return myChildren.get(0).getPreviousBlock(); + } + public void dispose() { super.dispose(); myChildren = null; diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java b/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java index da607feaca2e..96f38eef28cf 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java @@ -61,11 +61,11 @@ public class FormatterImpl extends FormatterEx } public Alignment createAlignment() { - return new AlignmentImpl(AlignmentImpl.Type.NORMAL); + return new AlignmentImpl(); } public Alignment createChildAlignment(final Alignment base) { - AlignmentImpl result = new AlignmentImpl(AlignmentImpl.Type.NORMAL); + AlignmentImpl result = new AlignmentImpl(); result.setParent(base); return result; } diff --git a/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java index 171ac65b1357..1c5b96d8cf6b 100644 --- a/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java @@ -90,6 +90,7 @@ class LeafBlockWrapper extends AbstractBlockWrapper { return mySymbolsAtTheLastLine; } + @Override public LeafBlockWrapper getPreviousBlock() { return myPreviousBlock; } @@ -102,10 +103,33 @@ class LeafBlockWrapper extends AbstractBlockWrapper { myNextBlock = nextBlock; } + @Override protected boolean indentAlreadyUsedBefore(final AbstractBlockWrapper child) { return false; } + @Override + protected IndentData getNumberOfSymbolsBeforeBlock() { + int spaces = getWhiteSpace().getSpaces(); + int indentSpaces = getWhiteSpace().getIndentSpaces(); + + if (getWhiteSpace().containsLineFeeds()) { + return new IndentData(indentSpaces, spaces); + } + + for (LeafBlockWrapper current = this.getPreviousBlock(); current != null; current = current.getPreviousBlock()) { + spaces += current.getWhiteSpace().getSpaces(); + spaces += current.getSymbolsAtTheLastLine(); + indentSpaces += current.getWhiteSpace().getIndentSpaces(); + if (current.getWhiteSpace().containsLineFeeds()) { + break; + } + } + return new IndentData(indentSpaces, spaces); + } + + + public void dispose() { super.dispose(); myPreviousBlock = null; diff --git a/platform/lang-impl/src/com/intellij/formatting/templateLanguages/TemplateLanguageBlock.java b/platform/lang-impl/src/com/intellij/formatting/templateLanguages/TemplateLanguageBlock.java index 7d1575c24fb8..92e084325957 100644 --- a/platform/lang-impl/src/com/intellij/formatting/templateLanguages/TemplateLanguageBlock.java +++ b/platform/lang-impl/src/com/intellij/formatting/templateLanguages/TemplateLanguageBlock.java @@ -64,7 +64,8 @@ public abstract class TemplateLanguageBlock extends AbstractBlock implements Blo for (ASTNode childNode = getNode().getFirstChildNode(); childNode != null; childNode = childNode.getTreeNext()) { if (FormatterUtil.containsWhiteSpacesOnly(childNode)) continue; if (shouldBuildBlockFor(childNode)) { - final TemplateLanguageBlock childBlock = myBlockFactory.createTemplateLanguageBlock(childNode, createChildWrap(childNode), null, mySettings); + final TemplateLanguageBlock childBlock = myBlockFactory + .createTemplateLanguageBlock(childNode, createChildWrap(childNode), createChildAlignment(childNode), null, mySettings); childBlock.setParent(this); tlChildren.add(childBlock); } @@ -133,5 +134,9 @@ public abstract class TemplateLanguageBlock extends AbstractBlock implements Blo protected Wrap createChildWrap(ASTNode child) { return Wrap.createWrap(Wrap.NONE, false); } + + protected Alignment createChildAlignment(ASTNode child) { + return null; + } } diff --git a/platform/lang-impl/src/com/intellij/formatting/templateLanguages/TemplateLanguageBlockFactory.java b/platform/lang-impl/src/com/intellij/formatting/templateLanguages/TemplateLanguageBlockFactory.java index cecc32749d6b..c6f2a3a80148 100644 --- a/platform/lang-impl/src/com/intellij/formatting/templateLanguages/TemplateLanguageBlockFactory.java +++ b/platform/lang-impl/src/com/intellij/formatting/templateLanguages/TemplateLanguageBlockFactory.java @@ -15,6 +15,7 @@ */ package com.intellij.formatting.templateLanguages; +import com.intellij.formatting.Alignment; import com.intellij.formatting.Wrap; import com.intellij.lang.ASTNode; import com.intellij.psi.codeStyle.CodeStyleSettings; @@ -31,6 +32,7 @@ import java.util.List; public interface TemplateLanguageBlockFactory { TemplateLanguageBlock createTemplateLanguageBlock(@NotNull ASTNode node, @Nullable Wrap wrap, + @Nullable Alignment alignment, @Nullable List foreignChildren, @NotNull CodeStyleSettings codeStyleSettings); } diff --git a/platform/lang-impl/src/com/intellij/formatting/templateLanguages/TemplateLanguageFormattingModelBuilder.java b/platform/lang-impl/src/com/intellij/formatting/templateLanguages/TemplateLanguageFormattingModelBuilder.java index da82a98880f3..a6027b2104a1 100644 --- a/platform/lang-impl/src/com/intellij/formatting/templateLanguages/TemplateLanguageFormattingModelBuilder.java +++ b/platform/lang-impl/src/com/intellij/formatting/templateLanguages/TemplateLanguageFormattingModelBuilder.java @@ -59,14 +59,14 @@ public abstract class TemplateLanguageFormattingModelBuilder implements Delegati return createDummyBlock(node); } if (builder == null) { - return createTemplateLanguageBlock(node, Wrap.createWrap(WrapType.NONE, false), Collections.emptyList(), settings); + return createTemplateLanguageBlock(node, Wrap.createWrap(WrapType.NONE, false), null, Collections.emptyList(), settings); } final FormattingModel model = builder.createModel(viewProvider.getPsi(dataLanguage), settings); List childWrappers = buildChildWrappers(model.getRootBlock()); if (childWrappers.size() == 1) { childWrappers = buildChildWrappers(childWrappers.get(0).getOriginal()); } - return createTemplateLanguageBlock(node, Wrap.createWrap(WrapType.NONE, false), filterBlocksByRange(childWrappers, node.getTextRange()), settings); + return createTemplateLanguageBlock(node, Wrap.createWrap(WrapType.NONE, false), null, filterBlocksByRange(childWrappers, node.getTextRange()), settings); } protected AbstractBlock createDummyBlock(final ASTNode node) { diff --git a/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java b/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java index 553bd6be00de..2fef940b3b23 100644 --- a/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java +++ b/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java @@ -734,6 +734,8 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre return value == null ? this : value; } + + @NotNull public Collection getChildren() { if (ourSettingsModificationCount != modificationCountForChildren) { @@ -762,7 +764,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre if (getElementInfoProvider() != null) { return getElementInfoProvider().isAlwaysShowsPlus((StructureViewTreeElement)getValue()); } - return getValue().getChildren().length > 0; + return true; } @Override @@ -771,7 +773,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre return getElementInfoProvider().isAlwaysLeaf((StructureViewTreeElement)getValue()); } - return getValue().getChildren().length == 0; + return false; } private StructureViewModel.ElementInfoProvider getElementInfoProvider() { @@ -791,6 +793,11 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre return new StructureViewTreeElementWrapper(myProject, child, myTreeModel); } + @Override + protected GroupWrapper createGroupWrapper(final Project project, Group group, final TreeModel treeModel) { + return new StructureViewGroup(project, group, treeModel); + } + public boolean equals(Object o) { if (o instanceof StructureViewTreeElementWrapper) { return Comparing.equal( @@ -820,6 +827,28 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre return o != null ? o.hashCode() : 0; } + + private class StructureViewGroup extends GroupWrapper { + public StructureViewGroup(Project project, Group group, TreeModel treeModel) { + super(project, group, treeModel); + } + + @Override + protected TreeElementWrapper createChildNode(TreeElement child) { + return new StructureViewTreeElementWrapper(getProject(), child, myTreeModel); + } + + + @Override + protected GroupWrapper createGroupWrapper(Project project, Group group, TreeModel treeModel) { + return new StructureViewGroup(project, group, treeModel); + } + + @Override + public boolean isAlwaysShowPlus() { + return true; + } + } } public String getHelpID() { diff --git a/platform/lang-impl/src/com/intellij/ide/util/DirectoryChooser.java b/platform/lang-impl/src/com/intellij/ide/util/DirectoryChooser.java index a7e74e8059f1..12f7e05815b8 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/DirectoryChooser.java +++ b/platform/lang-impl/src/com/intellij/ide/util/DirectoryChooser.java @@ -233,10 +233,10 @@ public class DirectoryChooser extends DialogWrapper { if (myDirectory != null) { VirtualFile virtualFile = myDirectory.getVirtualFile(); if (fileIndex.isInTestSourceContent(virtualFile)){ - return Icons.TEST_SOURCE_FOLDER; + return Icons.MODULES_TEST_SOURCE_FOLDER; } else if (fileIndex.isInSourceContent(virtualFile)){ - return Icons.SOURCE_FOLDERS_ICON; + return Icons.MODULES_SOURCE_FOLDERS_ICON; } } return Icons.FOLDER_ICON; diff --git a/platform/lang-impl/src/com/intellij/ide/util/treeView/smartTree/CachingChildrenTreeNode.java b/platform/lang-impl/src/com/intellij/ide/util/treeView/smartTree/CachingChildrenTreeNode.java index 5b4d1e7f2a2b..6cfd68b2228f 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/treeView/smartTree/CachingChildrenTreeNode.java +++ b/platform/lang-impl/src/com/intellij/ide/util/treeView/smartTree/CachingChildrenTreeNode.java @@ -155,7 +155,7 @@ public abstract class CachingChildrenTreeNode extends AbstractTreeNode children = group.getChildren(); for (TreeElement node : children) { - CachingChildrenTreeNode child = new TreeElementWrapper(getProject(), node, myTreeModel); + CachingChildrenTreeNode child = createChildNode(node); groupWrapper.addSubElement(child); AbstractTreeNode abstractTreeNode = ungroupedObjects.get(node); abstractTreeNode.setParent(groupWrapper); @@ -163,6 +163,10 @@ public abstract class CachingChildrenTreeNode extends AbstractTreeNode collectValues(List> ungrouped) { Map objects = new LinkedHashMap(); for (final AbstractTreeNode node : ungrouped) { @@ -174,11 +178,15 @@ public abstract class CachingChildrenTreeNode extends AbstractTreeNode createGroupNodes(Collection groups) { Map result = new THashMap(); for (Group group : groups) { - result.put(group, new GroupWrapper(getProject(), group, myTreeModel)); + result.put(group, createGroupWrapper(getProject(), group, myTreeModel)); } return result; } + protected GroupWrapper createGroupWrapper(final Project project, Group group, final TreeModel treeModel) { + return new GroupWrapper(project, group, treeModel); + } + private void rebuildSubtree() { initChildren(); diff --git a/platform/lang-impl/src/com/intellij/ide/util/treeView/smartTree/GroupWrapper.java b/platform/lang-impl/src/com/intellij/ide/util/treeView/smartTree/GroupWrapper.java index ab25f9da1e17..8596ba395653 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/treeView/smartTree/GroupWrapper.java +++ b/platform/lang-impl/src/com/intellij/ide/util/treeView/smartTree/GroupWrapper.java @@ -21,7 +21,7 @@ import com.intellij.openapi.project.Project; import java.util.Collection; -class GroupWrapper extends CachingChildrenTreeNode { +public class GroupWrapper extends CachingChildrenTreeNode { public GroupWrapper(Project project, Group value, TreeModel treeModel) { super(project, value, treeModel); clearChildren(); @@ -41,12 +41,11 @@ class GroupWrapper extends CachingChildrenTreeNode { clearChildren(); Collection children = getValue().getChildren(); for (TreeElement child : children) { - TreeElementWrapper childNode = new TreeElementWrapper(getProject(), child, myTreeModel); + TreeElementWrapper childNode = createChildNode(child); addSubElement(childNode); } } - protected void performTreeActions() { filterChildren(myTreeModel.getFilters()); groupChildren(myTreeModel.getGroupers()); diff --git a/platform/lang-impl/src/com/intellij/ide/util/treeView/smartTree/TreeElementWrapper.java b/platform/lang-impl/src/com/intellij/ide/util/treeView/smartTree/TreeElementWrapper.java index df4029513e31..dab90df455ff 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/treeView/smartTree/TreeElementWrapper.java +++ b/platform/lang-impl/src/com/intellij/ide/util/treeView/smartTree/TreeElementWrapper.java @@ -41,10 +41,6 @@ public class TreeElementWrapper extends CachingChildrenTreeNode{ } } - protected TreeElementWrapper createChildNode(final TreeElement child) { - return new TreeElementWrapper(getProject(), child, myTreeModel); - } - protected void performTreeActions() { filterChildren(myTreeModel.getFilters()); groupChildren(myTreeModel.getGroupers()); diff --git a/platform/lang-impl/src/com/intellij/injected/editor/EditorWindow.java b/platform/lang-impl/src/com/intellij/injected/editor/EditorWindow.java index 5f01a469f3e2..b9eef1d30246 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/EditorWindow.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/EditorWindow.java @@ -222,7 +222,7 @@ public class EditorWindow implements EditorEx, UserDataHolderEx { public EditorHighlighter getHighlighter() { EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme(); - EditorHighlighter highlighter = HighlighterFactory.createHighlighter(myInjectedFile.getFileType(), scheme, getProject()); + EditorHighlighter highlighter = HighlighterFactory.createHighlighter(myInjectedFile.getVirtualFile(), scheme, getProject()); highlighter.setText(getDocument().getText()); return highlighter; } diff --git a/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java b/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java index 0f72d83b9c20..ce2a0fc2e04e 100644 --- a/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java +++ b/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java @@ -102,6 +102,7 @@ public class GeneralColorsPage implements ColorSettingsPage { new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.selected.folding.outline"), EditorColors.SELECTED_FOLDING_TREE_COLOR, ColorDescriptor.Kind.FOREGROUND), new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.added.lines"), EditorColors.ADDED_LINES_COLOR, ColorDescriptor.Kind.BACKGROUND), new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.modified.lines"), EditorColors.MODIFIED_LINES_COLOR, ColorDescriptor.Kind.BACKGROUND), + new ColorDescriptor(OptionsBundle.message("options.java.color.descriptor.method.separator.color"), CodeInsightColors.METHOD_SEPARATORS_COLOR, ColorDescriptor.Kind.FOREGROUND), new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.console.background"), ConsoleViewContentType.CONSOLE_BACKGROUND_KEY, ColorDescriptor.Kind.BACKGROUND), }; diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java index 0c860a3ff64b..861611e4ff47 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java +++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java @@ -104,26 +104,26 @@ public class SdkConfigurationUtil { @Nullable public static Sdk setupSdk(final VirtualFile homeDir, final SdkType sdkType, final boolean silent) { + final Sdk[] sdks = ProjectJdkTable.getInstance().getAllJdks(); + final ProjectJdkImpl projectJdk; + try { + final String sdkName = createUniqueSdkName(sdkType, homeDir.getPath(), Arrays.asList(sdks)); + projectJdk = new ProjectJdkImpl(sdkName, sdkType); + projectJdk.setHomePath(homeDir.getPath()); + sdkType.setupSdkPaths(projectJdk); + } + catch (Exception e) { + if (!silent) { + Messages.showErrorDialog("Error configuring SDK: " + + e.getMessage() + + ".\nPlease make sure that " + + FileUtil.toSystemDependentName(homeDir.getPath()) + + " is a valid home path for this SDK type.", "Error configuring SDK"); + } + return null; + } return ApplicationManager.getApplication().runWriteAction(new NullableComputable() { public Sdk compute() { - final Sdk[] sdks = ProjectJdkTable.getInstance().getAllJdks(); - ProjectJdkImpl projectJdk; - try { - final String sdkName = createUniqueSdkName(sdkType, homeDir.getPath(), Arrays.asList(sdks)); - projectJdk = new ProjectJdkImpl(sdkName, sdkType); - projectJdk.setHomePath(homeDir.getPath()); - sdkType.setupSdkPaths(projectJdk); - } - catch (Exception e) { - if (!silent) { - Messages.showErrorDialog("Error configuring SDK: " + - e.getMessage() + - ".\nPlease make sure that " + - FileUtil.toSystemDependentName(homeDir.getPath()) + - " is a valid home path for this SDK type.", "Error configuring SDK"); - } - return null; - } ProjectJdkTable.getInstance().addJdk(projectJdk); return projectJdk; } diff --git a/platform/lang-impl/src/com/intellij/openapi/vcs/impl/ModuleVcsDetector.java b/platform/lang-impl/src/com/intellij/openapi/vcs/impl/ModuleVcsDetector.java index 7fec28d15608..ae9d4e74dc73 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vcs/impl/ModuleVcsDetector.java +++ b/platform/lang-impl/src/com/intellij/openapi/vcs/impl/ModuleVcsDetector.java @@ -29,6 +29,7 @@ import com.intellij.openapi.roots.ModuleRootListener; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.ProjectLevelVcsManager; @@ -82,10 +83,16 @@ public class ModuleVcsDetector implements ProjectComponent { } private class MyModulesListener extends ModuleAdapter implements ModuleRootListener { + private final List> myMappingsForRemovedModules = new ArrayList>(); + public void beforeRootsChange(ModuleRootEvent event) { + myMappingsForRemovedModules.clear(); } public void rootsChanged(ModuleRootEvent event) { + for (Pair mapping : myMappingsForRemovedModules) { + promptRemoveMapping(mapping.first, mapping.second); + } // the check calculates to true only before user has done any change to mappings, i.e. in case modules are detected/added automatically // on start etc (look inside) if (myVcsManager.needAutodetectMappings()) { @@ -94,11 +101,12 @@ public class ModuleVcsDetector implements ProjectComponent { } public void moduleAdded(final Project project, final Module module) { + myMappingsForRemovedModules.removeAll(getMappings(module)); autoDetectModuleVcsMapping(module); } public void beforeModuleRemoved(final Project project, final Module module) { - checkRemoveVcsRoot(module); + myMappingsForRemovedModules.addAll(getMappings(module)); } } @@ -183,27 +191,31 @@ public class ModuleVcsDetector implements ProjectComponent { } } - private void checkRemoveVcsRoot(final Module module) { + private List> getMappings(final Module module) { + List> result = new ArrayList>(); final VirtualFile[] files = ModuleRootManager.getInstance(module).getContentRoots(); final String moduleName = module.getName(); for(final VirtualFile file: files) { for(final VcsDirectoryMapping mapping: myVcsManager.getDirectoryMappings()) { if (FileUtil.toSystemIndependentName(mapping.getDirectory()).equals(file.getPath())) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - if (myProject.isDisposed()) return; - final String msg = VcsBundle.message("vcs.root.remove.prompt", FileUtil.toSystemDependentName(file.getPath()), moduleName); - int rc = Messages.showYesNoDialog(myProject, msg, VcsBundle.message("vcs.root.remove.title"), Messages.getQuestionIcon()); - if (rc == 0) { - myVcsManager.removeDirectoryMapping(mapping); - } - } - }, ModalityState.NON_MODAL); + result.add(new Pair(moduleName, mapping)); break; } } } + return result; } - + private void promptRemoveMapping(final String moduleName, final VcsDirectoryMapping mapping) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + if (myProject.isDisposed()) return; + final String msg = VcsBundle.message("vcs.root.remove.prompt", FileUtil.toSystemDependentName(mapping.getDirectory()), moduleName); + int rc = Messages.showYesNoDialog(myProject, msg, VcsBundle.message("vcs.root.remove.title"), Messages.getQuestionIcon()); + if (rc == 0) { + myVcsManager.removeDirectoryMapping(mapping); + } + } + }, ModalityState.NON_MODAL); + } } diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java index de48efbb8eed..ad3b8aa5eb0a 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java @@ -456,7 +456,7 @@ public class SingleInspectionProfilePanel extends JPanel { myTree.setCellRenderer(renderer); - myTree.setRootVisible(true); + myTree.setRootVisible(false); myTree.setShowsRootHandles(true); UIUtil.setLineStyleAngled(myTree); TreeToolTipHandler.install(myTree); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java index a4c463c9b29d..b2151518a7b1 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java @@ -520,29 +520,28 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec public void documentChanged(DocumentEvent event) { final Document document = event.getDocument(); final FileViewProvider viewProvider = getCachedViewProvider(document); - if (viewProvider != null) { - if (viewProvider.getVirtualFile().getFileType().isBinary()) return; + if (viewProvider == null) return; + if (viewProvider.getVirtualFile().getFileType().isBinary()) return; - final List files = viewProvider.getAllFiles(); - boolean commitNecessary = false; - for (PsiFile file : files) { - if (file == null || file instanceof PsiFileImpl && ((PsiFileImpl)file).getTreeElement() == null) continue; - final TextBlock textBlock = getTextBlock(document, file); - if (textBlock.isLocked()) continue; + final List files = viewProvider.getAllFiles(); + boolean commitNecessary = false; + for (PsiFile file : files) { + if (file == null || file instanceof PsiFileImpl && ((PsiFileImpl)file).getTreeElement() == null) continue; + final TextBlock textBlock = getTextBlock(document, file); + if (textBlock.isLocked()) continue; - if (mySmartPointerManager != null) { // mock tests - SmartPointerManagerImpl.unfastenBelts(file); - } - - textBlock.documentChanged(event); - assert file instanceof PsiFileImpl : event + "; file="+file+"; allFiles="+files+"; viewProvider="+viewProvider; - myUncommittedDocuments.add(document); - commitNecessary = true; + if (mySmartPointerManager != null) { // mock tests + SmartPointerManagerImpl.unfastenBelts(file); } - if (commitNecessary && ApplicationManager.getApplication().getCurrentWriteAction(ExternalChangeAction.class) != null){ - commitDocument(document); - } + textBlock.documentChanged(event); + assert file instanceof PsiFileImpl : event + "; file="+file+"; allFiles="+files+"; viewProvider="+viewProvider; + myUncommittedDocuments.add(document); + commitNecessary = true; + } + + if (commitNecessary && ApplicationManager.getApplication().getCurrentWriteAction(ExternalChangeAction.class) != null){ + commitDocument(document); } } diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/BasePlatformRefactoringAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/BasePlatformRefactoringAction.java new file mode 100644 index 000000000000..9880e9d21e12 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/BasePlatformRefactoringAction.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2010 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.refactoring.actions; + +import com.intellij.lang.Language; +import com.intellij.lang.LanguageRefactoringSupport; +import com.intellij.lang.refactoring.RefactoringSupportProvider; +import com.intellij.openapi.extensions.ExtensionPointListener; +import com.intellij.openapi.extensions.PluginDescriptor; +import org.jetbrains.annotations.Nullable; + +/** + * @author yole + */ +public abstract class BasePlatformRefactoringAction extends BaseRefactoringAction { + private Boolean myHidden = null; + + public BasePlatformRefactoringAction() { + LanguageRefactoringSupport.INSTANCE.addListener(new ExtensionPointListener() { + public void extensionAdded(RefactoringSupportProvider extension, @Nullable PluginDescriptor pluginDescriptor) { + myHidden = null; + } + + public void extensionRemoved(RefactoringSupportProvider extension, @Nullable PluginDescriptor pluginDescriptor) { + myHidden = null; + } + }); + } + + @Override + protected boolean isHidden() { + if (myHidden == null) { + myHidden = calcHidden(); + } + return myHidden.booleanValue(); + } + + private boolean calcHidden() { + for(Language l: Language.getRegisteredLanguages()) { + if (isAvailableForLanguage(l)) { + return false; + } + } + return true; + } +} diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java index 54e76c51dc97..9744892bed7e 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java @@ -87,6 +87,10 @@ public abstract class BaseRefactoringAction extends AnAction { disableAction(e); return; } + if (isHidden()) { + e.getPresentation().setVisible(false); + return; + } Editor editor = e.getData(PlatformDataKeys.EDITOR); PsiFile file = e.getData(LangDataKeys.PSI_FILE); @@ -127,6 +131,10 @@ public abstract class BaseRefactoringAction extends AnAction { } } + protected boolean isHidden() { + return false; + } + public static PsiElement getElementAtCaret(final Editor editor, final PsiFile file) { final int offset = fixCaretOffset(editor); PsiElement element = file.findElementAt(offset); diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/ExtractMethodAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/ExtractMethodAction.java index 882cb12af038..5a91122c1c35 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/ExtractMethodAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/ExtractMethodAction.java @@ -23,10 +23,7 @@ import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.psi.PsiElement; import com.intellij.refactoring.RefactoringActionHandler; -/** - * - */ -public class ExtractMethodAction extends BaseRefactoringAction { +public class ExtractMethodAction extends BasePlatformRefactoringAction { public ExtractMethodAction() { setInjectedContext(true); } diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/ExtractSuperclassAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/ExtractSuperclassAction.java index 14e313eb8095..02290346a898 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/ExtractSuperclassAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/ExtractSuperclassAction.java @@ -26,7 +26,7 @@ import com.intellij.psi.PsiFile; import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.lang.ElementsHandler; -public class ExtractSuperclassAction extends BaseRefactoringAction { +public class ExtractSuperclassAction extends BasePlatformRefactoringAction { public boolean isAvailableInEditorOnly() { return false; } diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/InlineAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/InlineAction.java index bdf332d44c63..a38458fca56e 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/InlineAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/InlineAction.java @@ -33,7 +33,7 @@ import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.inline.InlineRefactoringActionHandler; import org.jetbrains.annotations.Nullable; -public class InlineAction extends BaseRefactoringAction { +public class InlineAction extends BasePlatformRefactoringAction { public boolean isAvailableInEditorOnly() { return false; diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceConstantAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceConstantAction.java index 8afc3073ff3c..81a19b4a6b83 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceConstantAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceConstantAction.java @@ -23,7 +23,7 @@ import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.psi.PsiElement; import com.intellij.refactoring.RefactoringActionHandler; -public class IntroduceConstantAction extends BaseRefactoringAction { +public class IntroduceConstantAction extends BasePlatformRefactoringAction { public IntroduceConstantAction() { setInjectedContext(true); } diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceFieldAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceFieldAction.java index b84f1a1fe2c8..a5085c2a15cd 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceFieldAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceFieldAction.java @@ -23,7 +23,7 @@ import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.psi.PsiElement; import com.intellij.refactoring.RefactoringActionHandler; -public class IntroduceFieldAction extends BaseRefactoringAction { +public class IntroduceFieldAction extends BasePlatformRefactoringAction { public IntroduceFieldAction() { setInjectedContext(true); } diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceParameterAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceParameterAction.java index 9a06120f7b4a..607f6642b877 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceParameterAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceParameterAction.java @@ -31,7 +31,7 @@ import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.lang.Language; import com.intellij.lang.LanguageRefactoringSupport; -public class IntroduceParameterAction extends BaseRefactoringAction { +public class IntroduceParameterAction extends BasePlatformRefactoringAction { protected boolean isAvailableInEditorOnly() { return true; } diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceVariableAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceVariableAction.java index 9484f0e7b63d..aa91cf1f52a0 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceVariableAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/IntroduceVariableAction.java @@ -26,7 +26,7 @@ import com.intellij.refactoring.RefactoringActionHandler; /** * */ -public class IntroduceVariableAction extends BaseRefactoringAction { +public class IntroduceVariableAction extends BasePlatformRefactoringAction { public IntroduceVariableAction() { setInjectedContext(true); } diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/PullUpAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/PullUpAction.java index cdafb59e6928..2e65b2099895 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/PullUpAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/PullUpAction.java @@ -26,7 +26,7 @@ import com.intellij.psi.PsiFile; import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.lang.ElementsHandler; -public class PullUpAction extends BaseRefactoringAction { +public class PullUpAction extends BasePlatformRefactoringAction { public PullUpAction() { setInjectedContext(true); diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/PushDownAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/PushDownAction.java index 5fab549848d1..f3a755494b49 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/PushDownAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/PushDownAction.java @@ -27,7 +27,7 @@ import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.lang.ElementsHandler; -public class PushDownAction extends BaseRefactoringAction { +public class PushDownAction extends BasePlatformRefactoringAction { public PushDownAction() { setInjectedContext(true); diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/RenamePsiElementProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/rename/RenamePsiElementProcessor.java index 3668febb1a4f..f1d0d0f2bc2b 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/RenamePsiElementProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/RenamePsiElementProcessor.java @@ -93,7 +93,7 @@ public abstract class RenamePsiElementProcessor { if (element instanceof PsiFile) { return "refactoring.renameFile"; } - return null; + return "refactoring.renameDialogs"; } public boolean isToSearchInComments(final PsiElement element) { diff --git a/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java b/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java index 53fa5b1932d6..7dbc4a248c92 100644 --- a/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java +++ b/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java @@ -20,7 +20,7 @@ package com.intellij.ui; import com.intellij.concurrency.Job; -import com.intellij.concurrency.JobScheduler; +import com.intellij.concurrency.JobUtil; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.util.Alarm; @@ -90,8 +90,7 @@ public class DeferredIconImpl implements DeferredIcon { myLastTarget = new WeakReference(target); - final Job job = JobScheduler.getInstance().createJob("Evaluating deferred icon", Job.DEFAULT_PRIORITY); - job.addTask(new Runnable() { + JobUtil.submitToJobThread(new Runnable() { public void run() { int oldWidth = myDelegateIcon.getIconWidth(); myDelegateIcon = evaluate(); @@ -121,9 +120,7 @@ public class DeferredIconImpl implements DeferredIcon { } }); } - }); - - job.schedule(); + }, Job.DEFAULT_PRIORITY); } } diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index f8af228c6ea9..0983e62dbe45 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -929,7 +929,7 @@ public class AbstractTreeUi { forceUpdate = false; } - updateNodeChildren(node, pass, null, false, canSmartExpand, forceUpdate, false); + updateNodeChildren(node, pass, null, false, canSmartExpand, forceUpdate, false); } private boolean isToBuildInBackground(NodeDescriptor descriptor) { @@ -1256,39 +1256,48 @@ public class AbstractTreeUi { final Object element = getElementFor(node); - final LoadedChildren children = loadedChildren != null ? loadedChildren : new LoadedChildren(getChildrenFor(element)); + addToUpdating(node); - boolean processed; + try { + final LoadedChildren children = loadedChildren != null ? loadedChildren : new LoadedChildren(getChildrenFor(element)); - if (children.getElements().size() == 0) { - removeLoading(node, true); - processed = true; - } - else { - if (isAutoExpand(node)) { - addNodeAction(getElementFor(node), new NodeAction() { - public void onReady(final DefaultMutableTreeNode node) { - final TreePath path = new TreePath(node.getPath()); - if (getTree().isExpanded(path) || children.getElements().size() == 0) { - removeLoading(node, false); - } - else { - maybeYeild(new ActiveRunnable() { - public ActionCallback run() { - expand(element, null); - return new ActionCallback.Done(); - } - }, pass, node); - } - } - }, false); + boolean processed; + + if (children.getElements().size() == 0) { + removeLoading(node, true); + processed = true; } - processed = false; + else { + if (isAutoExpand(node)) { + addNodeAction(getElementFor(node), new NodeAction() { + public void onReady(final DefaultMutableTreeNode node) { + final TreePath path = new TreePath(node.getPath()); + if (getTree().isExpanded(path) || children.getElements().size() == 0) { + removeLoading(node, false); + } + else { + maybeYeild(new ActiveRunnable() { + public ActionCallback run() { + expand(element, null); + return new ActionCallback.Done(); + } + }, pass, node); + } + } + }, false); + } + processed = false; + } + + removeFromUpdating(node); + + processNodeActionsIfReady(node); + + return new Pair(processed, children); + } + finally { + removeFromUpdating(node); } - - processNodeActionsIfReady(node); - - return new Pair(processed, children); } private boolean removeIfLoading(TreeNode node) { @@ -3829,7 +3838,9 @@ public class AbstractTreeUi { DefaultMutableTreeNode parent = getParentBuiltNode(subtreeRoot); if (parent == null) { - addSubtreeToUpdate(subtreeRoot); + if (!getBuilder().isAlwaysShowPlus(getDescriptorFrom(subtreeRoot))) { + addSubtreeToUpdate(subtreeRoot); + } } else if (parent != subtreeRoot) { addNodeAction(getElementFor(subtreeRoot), new NodeAction() { public void onReady(DefaultMutableTreeNode parent) { @@ -3877,7 +3888,7 @@ public class AbstractTreeUi { return !myUnbuiltNodes.contains(node); } - static class LoadedChildren { + class LoadedChildren { private final List myElements; private final Map myDescriptors = new HashMap(); @@ -3888,7 +3899,9 @@ public class AbstractTreeUi { } void putDescriptor(Object element, NodeDescriptor descriptor, boolean isChanged) { - assert myElements.contains(element); + if (isUnitTestingMode()) { + assert myElements.contains(element); + } myDescriptors.put(element, descriptor); myChanges.put(descriptor, isChanged); } diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/CharsetToolkit.java b/platform/platform-api/src/com/intellij/openapi/vfs/CharsetToolkit.java index f48f0bda0131..eb6a3e093ccc 100644 --- a/platform/platform-api/src/com/intellij/openapi/vfs/CharsetToolkit.java +++ b/platform/platform-api/src/com/intellij/openapi/vfs/CharsetToolkit.java @@ -84,9 +84,9 @@ public class CharsetToolkit { private final Charset defaultCharset; private boolean enforce8Bit = false; - public static final byte[] UTF8_BOM = new byte[]{-17, -69, -65, }; - public static final byte[] UTF16LE_BOM = new byte[]{-1, -2, }; - public static final byte[] UTF16BE_BOM = new byte[]{-2, -1, }; + public static final byte[] UTF8_BOM = {-17, -69, -65, }; + public static final byte[] UTF16LE_BOM = {-1, -2, }; + public static final byte[] UTF16BE_BOM = {-2, -1, }; @NonNls public static final String FILE_ENCODING_PROPERTY = "file.encoding"; @NonNls private static final Map CHARSET_TO_BOM = new THashMap(); diff --git a/platform/platform-api/src/com/intellij/ui/switcher/QuickAccessSettings.java b/platform/platform-api/src/com/intellij/ui/switcher/QuickAccessSettings.java index d1dfb236f74e..7c969ad80f06 100644 --- a/platform/platform-api/src/com/intellij/ui/switcher/QuickAccessSettings.java +++ b/platform/platform-api/src/com/intellij/ui/switcher/QuickAccessSettings.java @@ -20,6 +20,7 @@ import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.KeyboardShortcut; import com.intellij.openapi.actionSystem.Shortcut; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ApplicationComponent; import com.intellij.openapi.keymap.Keymap; @@ -27,6 +28,7 @@ import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.keymap.KeymapManagerListener; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; @@ -48,7 +50,7 @@ import java.awt.event.*; import java.text.NumberFormat; import java.util.*; -public class QuickAccessSettings implements ApplicationComponent, Configurable, KeymapManagerListener, Disposable { +public class QuickAccessSettings implements ApplicationComponent, SearchableConfigurable, KeymapManagerListener, Disposable { private Set myModifierVks = new HashSet(); private Keymap myKeymap; @@ -108,6 +110,14 @@ public class QuickAccessSettings implements ApplicationComponent, Configurable, return myUi; } + public String getId() { + return "QuickAccess"; + } + + public Runnable enableSearch(String option) { + return null; + } + public void activeKeymapChanged(Keymap keymap) { KeymapManager mgr = KeymapManager.getInstance(); myKeymap = mgr.getActiveKeymap(); @@ -125,6 +135,9 @@ public class QuickAccessSettings implements ApplicationComponent, Configurable, } private void applyModifiersFromRegistry() { + Application app = ApplicationManager.getApplication(); + if (app != null && app.isUnitTestMode()) return; + String text = getModifierRegistryValue(); String[] vks = text.split(" "); diff --git a/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java b/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java index 02f361115f1b..6cc0baf83f94 100644 --- a/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java +++ b/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java @@ -180,7 +180,8 @@ public class Tree extends JTree implements ComponentWithEmptyText, Autoscroll, Q private void updateBusy() { if (myBusy) { if (myBusyIcon == null) { - myBusyIcon = new AsyncProcessIcon(toString()); + myBusyIcon = new AsyncProcessIcon(toString()).setUseMask(false); + myBusyIcon.setOpaque(false); myBusyIcon.setPaintPassiveIcon(false); add(myBusyIcon); } diff --git a/platform/platform-api/src/com/intellij/util/Icons.java b/platform/platform-api/src/com/intellij/util/Icons.java index 2efee2fc533b..a7315ceab7ca 100644 --- a/platform/platform-api/src/com/intellij/util/Icons.java +++ b/platform/platform-api/src/com/intellij/util/Icons.java @@ -122,6 +122,9 @@ public abstract class Icons { public static final Icon SOURCE_FOLDERS_ICON = IconLoader.getIcon("/nodes/sourceFolder.png"); public static final Icon TEST_SOURCE_FOLDER = IconLoader.getIcon("/nodes/testSourceFolder.png"); + public static final Icon MODULES_SOURCE_FOLDERS_ICON = IconLoader.getIcon("/modules/sourceRootClosed.png"); + public static final Icon MODULES_TEST_SOURCE_FOLDER = IconLoader.getIcon("/modules/testRootClosed.png"); + public static final Icon CONTENT_ROOT_ICON_OPEN = IconLoader.getIcon("/nodes/ModuleOpen.png"); public static final Icon CONTENT_ROOT_ICON_CLOSED = IconLoader.getIcon("/nodes/ModuleClosed.png"); diff --git a/platform/platform-api/src/com/intellij/util/net/NetUtils.java b/platform/platform-api/src/com/intellij/util/net/NetUtils.java index da07c2bd2b0e..c267534c5525 100644 --- a/platform/platform-api/src/com/intellij/util/net/NetUtils.java +++ b/platform/platform-api/src/com/intellij/util/net/NetUtils.java @@ -76,7 +76,7 @@ public class NetUtils { return ports; } - private static String getLocalHostString() { + public static String getLocalHostString() { // HACK for Windows with ipv6 String localHostString = "localhost"; try { diff --git a/platform/platform-api/src/com/intellij/util/ui/AnimatedIcon.java b/platform/platform-api/src/com/intellij/util/ui/AnimatedIcon.java index ea3db09bb08d..72144f1242a1 100644 --- a/platform/platform-api/src/com/intellij/util/ui/AnimatedIcon.java +++ b/platform/platform-api/src/com/intellij/util/ui/AnimatedIcon.java @@ -40,6 +40,7 @@ public abstract class AnimatedIcon extends JComponent implements Disposable { private final String myName; private boolean myLastPaintWasRunning; + private boolean myPaintingBgNow; protected AnimatedIcon(final String name) { myName = name; @@ -97,10 +98,8 @@ public abstract class AnimatedIcon extends JComponent implements Disposable { boolean changes = myAnimator.isRunning() != running; if (running) { - setOpaque(true); myAnimator.resume(); } else { - setOpaque(myPaintPassive); myAnimator.suspend(); } @@ -149,10 +148,18 @@ public abstract class AnimatedIcon extends JComponent implements Disposable { } protected void paintComponent(Graphics g) { - if (isOpaque() && (myAnimator.isRunning() || myPaintPassive || (myLastPaintWasRunning && !myAnimator.isRunning()))) { - g.setColor(UIUtil.getBgFillColor(this)); + if (myPaintingBgNow) return; + + if (isOpaque()) { + final Container parent = getParent(); + JComponent opaque = null; + if (parent instanceof JComponent) { + opaque = (JComponent)UIUtil.findNearestOpaque((JComponent)parent); + } + Color bg = opaque != null ? opaque.getBackground() : UIManager.getColor("Panel.background"); + g.setColor(bg); g.fillRect(0, 0, getWidth(), getHeight()); - } + } Icon icon; @@ -166,11 +173,15 @@ public abstract class AnimatedIcon extends JComponent implements Disposable { int x = (size.width - icon.getIconWidth()) / 2; int y = (size.height - icon.getIconHeight()) / 2; - icon.paintIcon(this, g, x, y); + paintIcon(g, icon, x, y); myLastPaintWasRunning = myAnimator.isRunning(); } + protected void paintIcon(Graphics g, Icon icon, int x, int y) { + icon.paintIcon(this, g, x, y); + } + protected Icon getPassiveIcon() { return myPaintPassive ? myPassiveIcon : myEmptyPassiveIcon; } @@ -179,4 +190,9 @@ public abstract class AnimatedIcon extends JComponent implements Disposable { public boolean isAnimated() { return true; } + + @Override + public String toString() { + return myName + " isRunning=" + myRunning + " isOpaque=" + isOpaque() + " paintPassive=" + myPaintPassive; + } } diff --git a/platform/platform-api/src/com/intellij/util/ui/AsyncProcessIcon.java b/platform/platform-api/src/com/intellij/util/ui/AsyncProcessIcon.java index 89328ddfb428..3146b7d36e2f 100644 --- a/platform/platform-api/src/com/intellij/util/ui/AsyncProcessIcon.java +++ b/platform/platform-api/src/com/intellij/util/ui/AsyncProcessIcon.java @@ -17,6 +17,7 @@ package com.intellij.util.ui; import com.intellij.openapi.util.IconLoader; +import com.intellij.ui.LayeredIcon; import org.jetbrains.annotations.NonNls; import javax.swing.*; @@ -27,8 +28,10 @@ import java.awt.event.ActionListener; public class AsyncProcessIcon extends AnimatedIcon { public static final int COUNT = 12; public static final int CYCLE_LENGTH = 800; - private static final Icon[] SMALL_ICONS = findIcons("/process/step_"); + + private static final Icon[] SMALL_ICONS = findIcons("/process/step_", "/process/step_mask.png"); private static final Icon SMALL_PASSIVE_ICON = IconLoader.getIcon("/process/step_passive.png"); + private boolean myUseMask; public AsyncProcessIcon(@NonNls String name) { this(name, SMALL_ICONS, SMALL_PASSIVE_ICON); @@ -38,18 +41,49 @@ public class AsyncProcessIcon extends AnimatedIcon { super(name); init(icons, passive, CYCLE_LENGTH, 0, -1); + + setUseMask(false); } - private static Icon[] findIcons(String prefix) { + public AsyncProcessIcon setUseMask(boolean useMask) { + myUseMask = useMask; + return this; + } + + @Override + protected void paintIcon(Graphics g, Icon icon, int x, int y) { + if (icon instanceof ProcessIcon) { + ((ProcessIcon)icon).setLayerEnabled(0, myUseMask); + } + super.paintIcon(g, icon, x, y); + + if (icon instanceof ProcessIcon) { + ((ProcessIcon)icon).setLayerEnabled(0, false); + } + } + + private static Icon[] findIcons(String prefix, String maskIconPath) { + Icon maskIcon = maskIconPath != null ? IconLoader.getIcon(maskIconPath) : null; Icon[] icons = new Icon[COUNT]; for (int i = 0; i <= COUNT - 1; i++) { - icons[i] = IconLoader.getIcon(prefix + (i + 1) + ".png"); + Icon eachIcon = IconLoader.getIcon(prefix + (i + 1) + ".png"); + if (maskIcon != null) { + icons[i] = new ProcessIcon(maskIcon, eachIcon); + } else { + icons[i] = eachIcon; + } } return icons; } + private static class ProcessIcon extends LayeredIcon { + private ProcessIcon(Icon mask, Icon stepIcon) { + super(mask, stepIcon); + } + } + public static class Big extends AsyncProcessIcon { - private static final Icon[] BIG_ICONS = findIcons("/process/big/step_"); + private static final Icon[] BIG_ICONS = findIcons("/process/big/step_", null); private static final Icon BIG_PASSIVE_ICON = IconLoader.getIcon("/process/big/step_passive.png"); public Big(@NonNls final String name) { @@ -66,7 +100,7 @@ public class AsyncProcessIcon extends AnimatedIcon { JPanel content = new JPanel(new FlowLayout()); - AsyncProcessIcon progress = new Big("Process"); + AsyncProcessIcon progress = new AsyncProcessIcon("Process"); content.add(progress); JButton button = new JButton("press me"); diff --git a/platform/platform-impl/src/com/intellij/concurrency/JobImpl.java b/platform/platform-impl/src/com/intellij/concurrency/JobImpl.java index b056309345d5..52b68ad38402 100644 --- a/platform/platform-impl/src/com/intellij/concurrency/JobImpl.java +++ b/platform/platform-impl/src/com/intellij/concurrency/JobImpl.java @@ -21,33 +21,37 @@ package com.intellij.concurrency; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.util.containers.ContainerUtil; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; public class JobImpl implements Job { - private final String myTitle; - private final List> myTasks = ContainerUtil.createEmptyCOWList(); - private final long myJobIndex = JobSchedulerImpl.currentJobIndex(); + private static volatile long ourJobsCounter = 0; + private final long myJobIndex = ourJobsCounter++; private final int myPriority; - private final List> myFutures = ContainerUtil.createEmptyCOWList(); - private volatile boolean myCanceled = false; + private final List> myFutures = new ArrayList>(); + private volatile boolean canceled = false; + private final AtomicInteger runningTasks = new AtomicInteger(); + private volatile boolean scheduled; - public JobImpl(String title, int priority) { - myTitle = title; + JobImpl(int priority) { myPriority = priority; } public String getTitle() { - return myTitle; + return null; } public void addTask(Callable task) { - checkNotStarted(); + checkNotScheduled(); - myTasks.add(task); + synchronized (myFutures) { + PrioritizedFutureTask future = createFuture(task, this, myJobIndex, myPriority); + myFutures.add(future); + } + runningTasks.incrementAndGet(); } public void addTask(Runnable task, T result) { @@ -63,124 +67,147 @@ public class JobImpl implements Job { final Application application = ApplicationManager.getApplication(); boolean callerHasReadAccess = application != null && application.isReadAccessAllowed(); - createFutures(callerHasReadAccess, false); - // Don't bother scheduling if we only have one processor or only one task - if (JobSchedulerImpl.CORES_COUNT >= 2 && myFutures.size() >= 2) { - for (PrioritizedFutureTask future : myFutures) { - JobSchedulerImpl.execute(future); + boolean reallySchedule; + PrioritizedFutureTask[] tasks = getTasks(); + synchronized (myFutures) { + reallySchedule = JobSchedulerImpl.CORES_COUNT >= 2 && myFutures.size() >= 2; + } + scheduled = true; + + if (!reallySchedule) { + for (PrioritizedFutureTask future : tasks) { + future.run(); } + return null; } - // http://gafter.blogspot.com/2006/11/thread-pool-puzzler.html - for (PrioritizedFutureTask future : myFutures) { - future.run(); + submitTasks(tasks, callerHasReadAccess, false); + + while (!isDone() && JobSchedulerImpl.stealAndRunTask()) { + int i = 0; } - return waitForTermination(); + // in case of imbalanced tasks one huge task can stuck running and we would fall to waitForTermination instead of doing useful work + //// http://gafter.blogspot.com/2006/11/thread-pool-puzzler.html + //for (PrioritizedFutureTask task : tasks) { + // task.run(); + //} + // + + waitForTermination(tasks); + return null; } - private void createFutures(boolean callerHasReadAccess, final boolean reportExceptions) { - int startTaskIndex = JobSchedulerImpl.currentTaskIndex(); - for (final Callable task : myTasks) { - final PrioritizedFutureTask future = new PrioritizedFutureTask(task, myJobIndex, startTaskIndex++, myPriority, callerHasReadAccess, - reportExceptions); - myFutures.add(future); - } - } - - public List waitForTermination() throws Throwable { - List results = new ArrayList(myFutures.size()); - + public void waitForTermination(PrioritizedFutureTask[] tasks) throws Throwable { Throwable ex = null; - for (Future f : myFutures) { - try { - T result = null; + try { + for (PrioritizedFutureTask f : tasks) { + // this loop is for workaround of mysterious bug + // when sometimes future hangs inside parkAndCheckForInterrupt() during unbounded get() while(true) { try { - result = f.get(10, TimeUnit.MILLISECONDS); + f.get(10, TimeUnit.MILLISECONDS); break; } catch (TimeoutException e) { - if (f.isDone() || f.isCancelled()) break; + if (f.isDone()) { + f.get(); // does awaitTermination(), and there is no chance to hang + break; + } } } - results.add(result); } - catch (CancellationException ignore) { - } - catch (ExecutionException e) { - cancel(); + } + catch (CancellationException ignore) { + // already cancelled + } + catch (ExecutionException e) { + cancel(); - Throwable cause = e.getCause(); - if (cause != null) { - ex = cause; - } + Throwable cause = e.getCause(); + if (cause != null) { + ex = cause; } } - // Future.get() exits when currently running is canceled, thus awaiter may get control before spawned tasks actually terminated, - // that's why additional join logic. - for (PrioritizedFutureTask future : myFutures) { - future.awaitTermination(); + if (ex != null) { + throw ex; } - - if (ex != null) throw ex; - - return results; } public void cancel() { checkScheduled(); - if (myCanceled) return; - myCanceled = true; + if (canceled) return; + canceled = true; - for (Future future : myFutures) { + PrioritizedFutureTask[] tasks = getTasks(); + for (PrioritizedFutureTask future : tasks) { future.cancel(false); } + runningTasks.set(0); } public boolean isCanceled() { checkScheduled(); - return myCanceled; + return canceled; } public void schedule() { checkCanSchedule(); + scheduled = true; - createFutures(false, true); + PrioritizedFutureTask[] tasks = getTasks(); - for (PrioritizedFutureTask future : myFutures) { - JobSchedulerImpl.execute(future); + submitTasks(tasks, false, true); + } + + public PrioritizedFutureTask[] getTasks() { + PrioritizedFutureTask[] tasks; + synchronized (myFutures) { + tasks = myFutures.toArray(new PrioritizedFutureTask[myFutures.size()]); } + return tasks; } public boolean isDone() { checkScheduled(); - for (Future future : myFutures) { - if (!future.isDone()) return false; - } - - return true; + return runningTasks.get() <= 0; } private void checkCanSchedule() { - checkNotStarted(); - if (myTasks.isEmpty()) { - throw new IllegalStateException("No tasks to run. You can't schedule a job which has no tasks"); + checkNotScheduled(); + synchronized (myFutures) { + if (myFutures.isEmpty()) { + throw new IllegalStateException("No tasks added. You can't schedule a job which has no tasks"); + } } } - private void checkNotStarted() { - if (!myFutures.isEmpty()) { + private void checkNotScheduled() { + if (scheduled) { throw new IllegalStateException("Already running. You can't call this method for a job which is already scheduled"); } } private void checkScheduled() { - if (myFutures.isEmpty()) { + if (!scheduled) { throw new IllegalStateException("Cannot call this method for not yet started job"); } } + + private static void submitTasks(PrioritizedFutureTask[] tasks, boolean callerHasReadAccess, boolean reportExceptions) { + for (final PrioritizedFutureTask future : tasks) { + JobSchedulerImpl.submitTask(future, callerHasReadAccess, reportExceptions); + } + } + + void taskDone() { + runningTasks.decrementAndGet(); + } + + private static PrioritizedFutureTask createFuture(Callable task, JobImpl job, long jobIndex, int priority) { + return new PrioritizedFutureTask(task, job, jobIndex, JobSchedulerImpl.currentTaskIndex(), priority); + } } diff --git a/platform/platform-impl/src/com/intellij/concurrency/JobSchedulerImpl.java b/platform/platform-impl/src/com/intellij/concurrency/JobSchedulerImpl.java index ad798b41baef..149c50b9c41e 100644 --- a/platform/platform-impl/src/com/intellij/concurrency/JobSchedulerImpl.java +++ b/platform/platform-impl/src/com/intellij/concurrency/JobSchedulerImpl.java @@ -20,106 +20,70 @@ package com.intellij.concurrency; import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.impl.ApplicationImpl; import org.jetbrains.annotations.NonNls; import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; @NonNls public class JobSchedulerImpl extends JobScheduler implements Disposable { - public static final int CORES_COUNT = /*1;//*/Runtime.getRuntime().availableProcessors(); + public static final int CORES_COUNT = /*1;//*/ Runtime.getRuntime().availableProcessors(); private static final ThreadFactory WORKERS_FACTORY = new ThreadFactory() { - int i; - public Thread newThread(final Runnable r) { - final Thread thread = new Thread(r, "JobScheduler pool " + i++ + "/" + CORES_COUNT); + private int threadSeq; + + public synchronized Thread newThread(final Runnable r) { + @NonNls String name = "JobScheduler pool " + threadSeq + "/" + CORES_COUNT; + final Thread thread = new Thread(r, name); thread.setPriority(Thread.NORM_PRIORITY); + threadSeq++; return thread; } }; - private static final Lock ourSuspensionLock = new ReentrantLock(); + private static final PriorityBlockingQueue ourQueue = new PriorityBlockingQueue(); + private static final MyExecutor ourExecutor = new MyExecutor(); - private static final PriorityBlockingQueue ourQueue = new PriorityBlockingQueue() { - public Runnable poll() { - final Runnable result = super.poll(); - - ourSuspensionLock.lock(); - try { - return result; - } - finally { - ourSuspensionLock.unlock(); - } - } - - public Runnable poll(final long timeout, final TimeUnit unit) throws InterruptedException { - final Runnable result = super.poll(timeout, unit); - - ourSuspensionLock.lock(); - try { - return result; - } - finally { - ourSuspensionLock.unlock(); - } - } - }; - private static final ThreadPoolExecutor ourExecutor = new ThreadPoolExecutor(CORES_COUNT, Integer.MAX_VALUE, 60 * 10, TimeUnit.SECONDS, - ourQueue, WORKERS_FACTORY) { - protected void beforeExecute(final Thread t, final Runnable r) { - PrioritizedFutureTask task = (PrioritizedFutureTask)r; - if (task.isParentThreadHasReadAccess()) { - ApplicationImpl.setExceptionalThreadWithReadAccessFlag(true); - } - task.signalStarted(); - - // TODO: hook up JobMonitor into thread locals - super.beforeExecute(t, r); - } - - protected void afterExecute(final Runnable r, final Throwable t) { - super.afterExecute(r, t); - ApplicationImpl.setExceptionalThreadWithReadAccessFlag(false); - PrioritizedFutureTask task = (PrioritizedFutureTask)r; - task.signalDone(); - // TODO: cleanup JobMonitor - } - }; - - private static volatile long ourJobsCounter = 0; - - public static void execute(Runnable task) { - ourExecutor.execute(task); - } - - public static int currentTaskIndex() { - final PrioritizedFutureTask topTask = (PrioritizedFutureTask)ourQueue.peek(); - return topTask == null ? 0 : topTask.getTaskIndex(); - } - - public static long currentJobIndex() { - return ourJobsCounter++; - } - - public static void suspend() { - ourSuspensionLock.lock(); - } - - public static void resume() { - ourSuspensionLock.unlock(); + static int currentTaskIndex() { + return ourQueue.size(); } public Job createJob(String title, int priority) { - return new JobImpl(title, priority); + return new JobImpl(priority); } public void dispose() { ((ThreadPoolExecutor)getScheduler()).getQueue().clear(); } + + static boolean stealAndRunTask() { + Runnable task = ourQueue.poll(); + if (task == null) return false; + + task.run(); + + return true; + } + + static void submitTask(PrioritizedFutureTask future, boolean callerHasReadAccess, boolean reportExceptions) { + future.beforeRun(callerHasReadAccess, reportExceptions); + ourExecutor.executeTask(future); + } + + private static class MyExecutor extends ThreadPoolExecutor { + private MyExecutor() { + super(CORES_COUNT, Integer.MAX_VALUE, 60 * 10, TimeUnit.SECONDS, ourQueue, WORKERS_FACTORY); + } + + private void executeTask(final PrioritizedFutureTask task) { + super.execute(task); + } + + @Override + public void execute(Runnable command) { + throw new IllegalStateException("Use executeTask() to submit PrioritizedFutureTasks only"); + } + } } diff --git a/platform/lang-impl/src/com/intellij/concurrency/JobUtil.java b/platform/platform-impl/src/com/intellij/concurrency/JobUtil.java similarity index 57% rename from platform/lang-impl/src/com/intellij/concurrency/JobUtil.java rename to platform/platform-impl/src/com/intellij/concurrency/JobUtil.java index 021c9ffe18e9..93ff2a501931 100644 --- a/platform/lang-impl/src/com/intellij/concurrency/JobUtil.java +++ b/platform/platform-impl/src/com/intellij/concurrency/JobUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2010 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. @@ -20,12 +20,14 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.impl.ProgressManagerImpl; import com.intellij.openapi.progress.util.ProgressWrapper; import com.intellij.util.Processor; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import java.util.Collection; +import java.util.List; +import java.util.concurrent.Callable; /** * @author cdr @@ -34,30 +36,30 @@ import java.util.Collection; public class JobUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.concurrency.JobUtil"); - /** - * @param things to process concurrently - * @param thingProcessor to be invoked concurrently on each element from the collection - * @param jobName the name of the job that invokes all the tasks - * @return false if tasks have been canceled - * @throws ProcessCanceledException if at least one task has thrown ProcessCanceledException - */ - public static boolean invokeConcurrentlyForAll(@NotNull Collection things, @NotNull final Processor thingProcessor, @NotNull @NonNls String jobName) throws ProcessCanceledException { + private static boolean invokeConcurrentlyForAll(@NotNull final List things, @NotNull final Processor thingProcessor, @NotNull @NonNls String jobName) throws ProcessCanceledException { if (things.isEmpty()) { return true; } if (things.size() == 1) { - T t = things.iterator().next(); + T t = things.get(0); return thingProcessor.process(t); } - final Job job = JobScheduler.getInstance().createJob(jobName, Job.DEFAULT_PRIORITY); + final Job job = new JobImpl(Job.DEFAULT_PRIORITY); - for (final T thing : things) { - job.addTask(new Runnable(){ + final int chunkSize = Math.max(1, things.size() / JobSchedulerImpl.CORES_COUNT / 100); + for (int i = 0; i < things.size(); i += chunkSize) { + // this job chunk is i..i+chunkSize-1 + final int finalI = i; + job.addTask(new Runnable() { public void run() { try { - if (!thingProcessor.process(thing)) { - job.cancel(); + for (int k = finalI; k < finalI + chunkSize && k < things.size(); k++) { + T thing = things.get(k); + if (!thingProcessor.process(thing)) { + job.cancel(); + break; + } } } catch (ProcessCanceledException e) { @@ -81,22 +83,51 @@ public class JobUtil { return !job.isCanceled(); } - // execute in multiple threads, with checkCanceled in each delegated to our current progress - public static boolean invokeConcurrentlyUnderMyProgress(@NotNull Collection things, + /** + * Schedules concurrent execution of #thingProcessor over each element of #things and waits for completion + * With checkCanceled in each thread delegated to our current progress + * @param things to process concurrently + * @param thingProcessor to be invoked concurrently on each element from the collection + * @param jobName the name of the job that invokes all the tasks + * @return false if tasks have been canceled + * or at least one processor returned false + * or threw exception + * or we were unable to start read action in at least one thread + * @throws ProcessCanceledException if at least one task has thrown ProcessCanceledException + */ + public static boolean invokeConcurrentlyUnderMyProgress(@NotNull List things, @NotNull final Processor thingProcessor, @NotNull @NonNls String jobName) throws ProcessCanceledException { final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + final ProgressWrapper wrapper = ProgressWrapper.wrap(indicator); return invokeConcurrentlyForAll(things, new Processor() { public boolean process(final T t) { final boolean[] result = new boolean[1]; - ProgressManager.getInstance().runProcess(new Runnable() { + ((ProgressManagerImpl)ProgressManager.getInstance()).executeProcessUnderProgress(new Runnable() { public void run() { result[0] = thingProcessor.process(t); } - }, ProgressWrapper.wrap(indicator)); + }, wrapper); return result[0]; } }, jobName); } + public static Job submitToJobThread(@NotNull final Runnable action, int priority) { + Job job = new JobImpl(priority); + Callable callable = new Callable() { + public Void call() throws Exception { + try { + action.run(); + } + catch (ProcessCanceledException ignored) { + // since it's the only task in the job, nothing to cancel + } + return null; + } + }; + job.addTask(callable); + job.schedule(); + return job; + } } diff --git a/platform/platform-impl/src/com/intellij/concurrency/PrioritizedFutureTask.java b/platform/platform-impl/src/com/intellij/concurrency/PrioritizedFutureTask.java index ad7855f2002e..c19fa37cbb7a 100644 --- a/platform/platform-impl/src/com/intellij/concurrency/PrioritizedFutureTask.java +++ b/platform/platform-impl/src/com/intellij/concurrency/PrioritizedFutureTask.java @@ -19,112 +19,91 @@ */ package com.intellij.concurrency; -import com.intellij.openapi.application.RuntimeInterruptedException; +import com.intellij.openapi.application.ex.ApplicationManagerEx; +import com.intellij.openapi.application.impl.ApplicationImpl; import com.intellij.openapi.diagnostic.Logger; import java.util.concurrent.Callable; -import java.util.concurrent.FutureTask; -import java.util.concurrent.ExecutionException; import java.util.concurrent.CancellationException; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; -public class PrioritizedFutureTask extends FutureTask implements Comparable { +class PrioritizedFutureTask extends FutureTask implements Comparable { private static final Logger LOG = Logger.getInstance("#com.intellij.concurrency.PrioritizedFutureTask"); + private final JobImpl myJob; private final long myJobIndex; private final int myTaskIndex; private final int myPriority; - private final boolean myParentThreadHasReadAccess; - private final boolean myReportExceptions; - private final Lock myLock; - private volatile Condition myDoneCondition; + private volatile boolean myParentThreadHasReadAccess; + private volatile boolean myReportExceptions; - public PrioritizedFutureTask(final Callable callable, long jobIndex, int taskIndex, int priority, final boolean parentThreadHasReadAccess, boolean reportExceptions) { + PrioritizedFutureTask(final Callable callable, JobImpl job, long jobIndex, int taskIndex, int priority) { super(callable); + myJob = job; myJobIndex = jobIndex; myTaskIndex = taskIndex; myPriority = priority; + } + + public void beforeRun(boolean parentThreadHasReadAccess, boolean reportExceptions) { myParentThreadHasReadAccess = parentThreadHasReadAccess; myReportExceptions = reportExceptions; - - myLock = new ReentrantLock(); - } - - public boolean isParentThreadHasReadAccess() { - return myParentThreadHasReadAccess; - } - - public int compareTo(final PrioritizedFutureTask o) { - if (getPriority() != o.getPriority()) return getPriority() - o.getPriority(); - if (getTaskIndex() != o.getTaskIndex()) return getTaskIndex() - o.getTaskIndex(); - if (getJobIndex() != o.getJobIndex()) return getJobIndex() < o.getJobIndex() ? -1 : 1; - return 0; - } - - public long getJobIndex() { - return myJobIndex; - } - - public int getTaskIndex() { - return myTaskIndex; - } - - public int getPriority() { - return myPriority; - } - - public void signalStarted() { - myLock.lock(); - try { - myDoneCondition = myLock.newCondition(); - } - finally { - myLock.unlock(); - } - } - - public void signalDone() { - myLock.lock(); - try { - myDoneCondition.signalAll(); - myDoneCondition = null; - } - finally { - myLock.unlock(); - } - } - - public void awaitTermination() { - myLock.lock(); - try { - if (myDoneCondition == null) return; - myDoneCondition.await(); - } - catch (InterruptedException e) { - throw new RuntimeInterruptedException(e); - } - finally { - myLock.unlock(); - } } @Override - protected void done() { - if (myReportExceptions) { - // let exceptions during execution manifest themselves - try { - get(); + public void run() { + Runnable runnable = new Runnable() { + public void run() { + try { + if (myJob.isCanceled()) { + //set(null); + cancel(false); //todo cancel or set? + } + else { + PrioritizedFutureTask.super.run(); + } + } + finally { + try { + if (myReportExceptions) { + // let exceptions during execution manifest themselves + PrioritizedFutureTask.super.get(); + } + } + catch (CancellationException ignored) { + } + catch (InterruptedException e) { + LOG.error(e); + } + catch (ExecutionException e) { + LOG.error(e); + } + finally { + myJob.taskDone(); + //myDoneCondition.up(); + } + } } - catch (CancellationException e) { - //ignore + }; + if (myParentThreadHasReadAccess) { + if (ApplicationManagerEx.getApplicationEx().isUnitTestMode()) { + // all tests unfortunately are run from within write action, so they cannot really run read action in any thread + ApplicationImpl.setExceptionalThreadWithReadAccessFlag(true); } - catch (InterruptedException e) { - LOG.error(e); - } - catch (ExecutionException e) { - LOG.error(e); + // have to start "real" read action so that we cannot start write action until we are finished here + if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(runnable)) { + myJob.cancel(); } } + else { + runnable.run(); + } + } + + public int compareTo(final PrioritizedFutureTask o) { + int priorityDelta = myPriority - o.myPriority; + if (priorityDelta != 0) return priorityDelta; + if (myJobIndex != o.myJobIndex) return myJobIndex < o.myJobIndex ? -1 : 1; + return myTaskIndex - o.myTaskIndex; } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/execution/process/ColoredProcessHandler.java b/platform/platform-impl/src/com/intellij/execution/process/ColoredProcessHandler.java index c244ed559f3a..38678af67035 100644 --- a/platform/platform-impl/src/com/intellij/execution/process/ColoredProcessHandler.java +++ b/platform/platform-impl/src/com/intellij/execution/process/ColoredProcessHandler.java @@ -65,7 +65,7 @@ public class ColoredProcessHandler extends OSProcessHandler { return super.getCharset(); } - public void notifyTextAvailable(final String text, final Key outputType) { + public final void notifyTextAvailable(final String text, final Key outputType) { if (outputType != ProcessOutputTypes.STDOUT) { textAvailable(text, outputType); return; diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java index 6b45ee24986f..04a846720111 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java @@ -17,7 +17,6 @@ package com.intellij.ide; import com.intellij.Patches; -import com.intellij.concurrency.JobSchedulerImpl; import com.intellij.ide.dnd.DnDManager; import com.intellij.ide.dnd.DnDManagerImpl; import com.intellij.openapi.Disposable; @@ -363,14 +362,12 @@ public class IdeEventQueue extends EventQueue { AWTEvent oldEvent = myCurrentEvent; myCurrentEvent = e; - JobSchedulerImpl.suspend(); try { _dispatchEvent(e); } finally { myIsInInputEvent = wasInputEvent; myCurrentEvent = oldEvent; - JobSchedulerImpl.resume(); for (EventDispatcher each : myPostprocessors) { each.dispatch(e); @@ -566,24 +563,24 @@ public class IdeEventQueue extends EventQueue { || queue.peekEvent(MouseEvent.MOUSE_CLICKED) != null; if (!mouseEventsAhead) { - Window showingWindow = mgr.getActiveWindow(); - if (showingWindow != null) { - final IdeFocusManager fm = IdeFocusManager.findInstanceByComponent(showingWindow); - fm.doWhenFocusSettlesDown(new Runnable() { - public void run() { - if (mgr.getFocusOwner() == null) { - final Application app = ApplicationManager.getApplication(); - if (app != null && app.isActive()) { - fm.requestDefaultFocus(false); - } + Window showingWindow = mgr.getActiveWindow(); + if (showingWindow != null) { + final IdeFocusManager fm = IdeFocusManager.findInstanceByComponent(showingWindow); + fm.doWhenFocusSettlesDown(new Runnable() { + public void run() { + if (mgr.getFocusOwner() == null) { + final Application app = ApplicationManager.getApplication(); + if (app != null && app.isActive()) { + fm.requestDefaultFocus(false); } } - }); - } + } + }); } } } } + } private void enterSuspendModeIfNeeded(AWTEvent e) { if (e instanceof KeyEvent) { diff --git a/platform/platform-impl/src/com/intellij/ide/actions/QuickChangeLookAndFeel.java b/platform/platform-impl/src/com/intellij/ide/actions/QuickChangeLookAndFeel.java index 080903817d03..a7ee3d57fe39 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/QuickChangeLookAndFeel.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/QuickChangeLookAndFeel.java @@ -16,10 +16,10 @@ package com.intellij.ide.actions; import com.intellij.ide.ui.LafManager; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import javax.swing.*; @@ -32,9 +32,8 @@ public class QuickChangeLookAndFeel extends QuickSwitchSchemeAction { final LafManager manager = LafManager.getInstance(); final UIManager.LookAndFeelInfo[] lfs = manager.getInstalledLookAndFeels(); final UIManager.LookAndFeelInfo current = manager.getCurrentLookAndFeel(); - for (int i = 0; i < lfs.length; i++) { - final UIManager.LookAndFeelInfo lf = lfs[i]; - group.add(new AnAction(lf.getName(), "", lf == current ? ourCurrentAction : ourNotCurrentAction) { + for (final UIManager.LookAndFeelInfo lf : lfs) { + group.add(new DumbAwareAction(lf.getName(), "", lf == current ? ourCurrentAction : ourNotCurrentAction) { public void actionPerformed(AnActionEvent e) { manager.setCurrentLookAndFeel(lf); manager.updateUI(); diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionPopupMenuImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionPopupMenuImpl.java index 5014ab460cb7..d78f73e66338 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionPopupMenuImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionPopupMenuImpl.java @@ -20,6 +20,16 @@ import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.ActionPopupMenu; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationAdapter; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.ActionCallback; +import com.intellij.openapi.wm.FocusCommand; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.openapi.wm.IdeFrame; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.openapi.wm.impl.IdeFrameImpl; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,19 +37,25 @@ import javax.swing.*; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import java.awt.*; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; /** * @author Anton Katilin * @author Vladimir Kondratyev */ -final class ActionPopupMenuImpl implements ActionPopupMenu { +final class ActionPopupMenuImpl extends ApplicationAdapter implements ActionPopupMenu { private final MyMenu myMenu; private final ActionManagerImpl myManager; + private Application myApp; + private IdeFrame myFrame; + public ActionPopupMenuImpl(String place, @NotNull ActionGroup group, ActionManagerImpl actionManager, @Nullable PresentationFactory factory) { myManager = actionManager; myMenu = new MyMenu(place, group, factory); + myApp = ApplicationManager.getApplication(); } public JPopupMenu getComponent() { @@ -132,18 +148,34 @@ final class ActionPopupMenuImpl implements ActionPopupMenu { y -= invisibleHeight; } + if (myApp != null) { + if (myApp.isActive()) { + Component frame = UIUtil.findUltimateParent(component); + if (frame instanceof IdeFrame) { + myFrame = (IdeFrame)frame; + } + myApp.addApplicationListener(ActionPopupMenuImpl.this); + } + } + super.show(component, x, y); } private class MyPopupMenuListener implements PopupMenuListener { public void popupMenuCanceled(PopupMenuEvent e) { - myManager.removeActionPopup(ActionPopupMenuImpl.this); - MyMenu.this.removeAll(); + disposeMenu(); } public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + disposeMenu(); + } + + private void disposeMenu() { myManager.removeActionPopup(ActionPopupMenuImpl.this); MyMenu.this.removeAll(); + if (myApp != null) { + myApp.removeApplicationListener(ActionPopupMenuImpl.this); + } } public void popupMenuWillBecomeVisible(PopupMenuEvent e) { @@ -154,4 +186,12 @@ final class ActionPopupMenuImpl implements ActionPopupMenu { } } } + + @Override + public void applicationDeactivated(IdeFrame ideFrame) { + if (myFrame == ideFrame) { + myMenu.setVisible(false); + } + } + } diff --git a/platform/platform-impl/src/com/intellij/openapi/application/ex/ApplicationEx.java b/platform/platform-impl/src/com/intellij/openapi/application/ex/ApplicationEx.java index a59f69738d88..69f6416d242b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/ex/ApplicationEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/ex/ApplicationEx.java @@ -99,6 +99,8 @@ public interface ApplicationEx extends Application { void assertIsDispatchThread(@Nullable JComponent component); + void runEdtSafeAction(@NotNull Runnable runnable); + /** * Grab the lock and run the action, in a nonblocking fashion * @return true if action was run while holding the lock, false if was unable to get the lock and action was not run diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index 255dd7b794c0..2c616ab1dbb2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -141,6 +141,8 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application private Boolean myActive; + private static ThreadLocal ourEdtSafe = new ThreadLocal(); + protected void boostrapPicoContainer() { super.boostrapPicoContainer(); getPicoContainer().registerComponentImplementation(IComponentStore.class, StoresFactory.getApplicationStoreClass()); @@ -857,12 +859,32 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application } if (ourDispatchThread == currentThread) return; + Integer safeCounter = ourEdtSafe.get(); + if (safeCounter != null && safeCounter > 0) return; + LOG.error(message, "Current thread: " + describe(Thread.currentThread()), "Our dispatch thread:" + describe(ourDispatchThread), "SystemEventQueueThread: " + describe(getEventQueueThread())); } + public void runEdtSafeAction(@NotNull Runnable runnable) { + Integer value = ourEdtSafe.get(); + if (value == null) { + value = Integer.valueOf(0); + } + + ourEdtSafe.set(value + 1); + + try { + runnable.run(); + } + finally { + int newValue = ourEdtSafe.get() - 1; + ourEdtSafe.set(newValue >= 1 ? newValue : null); + } + } + public void assertIsDispatchThread(@Nullable final JComponent component) { if (component == null) return; @@ -1026,8 +1048,9 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application } public void saveSettings() { - if (myDoNotSave || isUnitTestMode() || isHeadlessEnvironment()) return; - _saveSettings(); + if (!myDoNotSave && !isUnitTestMode() && !isHeadlessEnvironment()) { + _saveSettings(); + } } public void saveAll() { diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java index 5c8b9c623c4b..30b3a1af1345 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java @@ -253,6 +253,11 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap clearUndoRedoQueue(DocumentReferenceManager.getInstance().create(file)); } + @TestOnly + public void clearUndoRedoQueueInTests(Document document) { + clearUndoRedoQueue(DocumentReferenceManager.getInstance().create(document)); + } + protected void compact() { if (myCurrentOperationState == NONE && myCommandTimestamp % COMMAND_TO_RUN_COMPACT == 0) { doCompact(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index 1f097c5ae77a..2eafb38d65a9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -40,6 +40,7 @@ import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.editor.event.EditorMouseEventArea; import com.intellij.openapi.editor.ex.*; import com.intellij.openapi.editor.markup.*; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.SystemInfo; import com.intellij.util.containers.HashMap; @@ -1161,7 +1162,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse updateSize(); } - private class CloseAnnotationsAction extends AnAction { + private class CloseAnnotationsAction extends DumbAwareAction { public CloseAnnotationsAction() { super(EditorBundle.message("close.editor.annotations.action.name")); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionImpl.java index 4c57b9115f8f..1dbf86ed25cd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionImpl.java @@ -70,7 +70,7 @@ public class FoldRegionImpl extends RangeMarkerImpl implements FoldRegion { } public boolean isValid() { - return super.isValid() && getStartOffset() + 1 < getEndOffset(); + return super.isValid() && myStart + 1 < myEnd; } public void setExpandedInternal(boolean toExpand) { diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java index 4a06e76e6ee4..0f5a67f23b3b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java @@ -22,7 +22,9 @@ import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ex.ApplicationEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.options.*; import com.intellij.openapi.options.ex.GlassPanel; @@ -321,11 +323,16 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat myConfigurable2LoadCallback.put(configurable, result); myLoadingDecorator.startLoading(false); - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + final Application app = ApplicationManager.getApplication(); + app.executeOnPooledThread(new Runnable() { public void run() { - ApplicationManager.getApplication().runReadAction(new Runnable() { + app.runReadAction(new Runnable() { public void run() { - initConfigurable(configurable).notifyWhenDone(result); + ((ApplicationEx)app).runEdtSafeAction(new Runnable() { + public void run() { + initConfigurable(configurable).notifyWhenDone(result); + } + }); } }); } diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java index 1343e05fc333..6732d7adf5f4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java @@ -34,6 +34,7 @@ import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.BuildNumber; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.text.StringUtil; @@ -140,6 +141,15 @@ public class PluginDownloader { LOG.info("Plugin " + myPluginId + ": current version (max) " + myPluginVersion); return false; //was not updated } + final BuildNumber currentBuildNumber = ApplicationInfo.getInstance().getBuild(); + final BuildNumber sinceBuild = BuildNumber.fromString(descriptor.getSinceBuild()); + if (sinceBuild != null && sinceBuild.compareTo(currentBuildNumber) > 0) { + return false; + } + final BuildNumber untilBuild = BuildNumber.fromString(descriptor.getUntilBuild()); + if (untilBuild != null && untilBuild.compareTo(currentBuildNumber) < 0) { + return false; + } } return true; } diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.java index 876b9c19f9ff..c1645cdf3f26 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.java @@ -293,7 +293,7 @@ public class UpdateSettingsConfigurable extends BaseConfigurable implements Sear public void actionPerformed(final ActionEvent e) { try { if (UpdateChecker.checkPluginsHost(getTextField().getText(), new ArrayList())) { - showInfoMessage(myParentComponent, "Plugins Host was sucessfully checked", "Check Plugins Host"); + showInfoMessage(myParentComponent, "Plugins Host was successfully checked", "Check Plugins Host"); } else { showErrorDialog(myParentComponent, "Plugin descriptions contain some errors. Please, check idea.log for details."); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java index 6a228037cee3..91c4007d4fd4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java @@ -82,7 +82,6 @@ public class InfoAndProgressPanel extends JPanel implements StatusBarPatch { myCompoundBorder = BorderFactory.createCompoundBorder(new StatusBarImpl.SeparatorBorder.Left(), new EmptyBorder(0, 2, 0, 2)); myProgressIcon = new AsyncProcessIcon("Background process"); - myProgressIcon.setOpaque(true); myProgressIcon.addMouseListener(new MouseAdapter() { @Override @@ -256,7 +255,12 @@ public class InfoAndProgressPanel extends JPanel implements StatusBarPatch { setLayout(new InlineLayout()); add(myInfoPanel); - final JPanel inlinePanel = new JPanel(new BorderLayout()); + final JPanel inlinePanel = new JPanel(new BorderLayout()) { + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + } + }; inline.getComponent().setBorder(new EmptyBorder(0, 0, 0, 2)); inlinePanel.add(inline.getComponent(), BorderLayout.CENTER); diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 30755be2056b..1b78bc8b7508 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -29,6 +29,7 @@ import com.intellij.openapi.wm.ex.ToolWindowManagerListener; import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.text.AttributeSet; @@ -41,6 +42,8 @@ import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.util.Arrays; +import java.util.ListIterator; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -92,6 +95,11 @@ public abstract class SpeedSearchBase { protected abstract void selectElement(Object element, String selectedText); + protected ListIterator getElementIterator(int startingIndex) { + final Object[] allElements = getAllElements(); + return Arrays.asList(allElements).listIterator(startingIndex < 0? allElements.length : startingIndex); + } + public void addChangeListener(PropertyChangeListener listener) { myChangeSupport.addPropertyChangeListener(listener); } @@ -191,62 +199,80 @@ public abstract class SpeedSearchBase { } } + @Nullable private Object findNextElement(String s) { - String _s = s.trim(); - Object[] elements = getAllElements(); - if (elements.length == 0) return null; - int selectedIndex = getSelectedIndex(); - for (int i = selectedIndex + 1; i < elements.length; i++) { - Object element = elements[i]; + final String _s = s.trim(); + final int selectedIndex = getSelectedIndex(); + final ListIterator it = getElementIterator(selectedIndex + 1); + final Object current; + if (it.hasPrevious()) { + current = it.previous(); + it.next(); + } + else current = null; + while (it.hasNext()) { + final Object element = it.next(); if (isMatchingElement(element, _s)) return element; } - return selectedIndex != -1 ? elements[selectedIndex] : null; // return current + return current; } + @Nullable private Object findPreviousElement(String s) { - String _s = s.trim(); - Object[] elements = getAllElements(); - if (elements.length == 0) return null; - int selectedIndex = getSelectedIndex(); - for (int i = selectedIndex - 1; i >= 0; i--) { - Object element = elements[i]; + final String _s = s.trim(); + final int selectedIndex = getSelectedIndex(); + if (selectedIndex < 0) return null; + final ListIterator it = getElementIterator(selectedIndex); + final Object current; + if (it.hasNext()) { + current = it.next(); + it.previous(); + } + else current = null; + while (it.hasPrevious()) { + final Object element = it.previous(); if (isMatchingElement(element, _s)) return element; } - return selectedIndex != -1 ? elements[selectedIndex] : null; // return current + return selectedIndex != -1? current : null; } + @Nullable private Object findElement(String s) { - String _s = s.trim(); - Object[] elements = getAllElements(); + final String _s = s.trim(); int selectedIndex = getSelectedIndex(); if (selectedIndex < 0) { selectedIndex = 0; } - for (int i = selectedIndex; i < elements.length; i++) { - Object element = elements[i]; + final ListIterator it = getElementIterator(selectedIndex); + while (it.hasNext()) { + final Object element = it.next(); if (isMatchingElement(element, _s)) return element; } - for (int i = 0; i < selectedIndex; i++) { - Object element = elements[i]; - if (isMatchingElement(element, _s)) return element; + if (selectedIndex > 0) { + while (it.hasPrevious()) it.previous(); + while (it.hasNext() && it.nextIndex() != selectedIndex) { + final Object element = it.next(); + if (isMatchingElement(element, _s)) return element; + } } return null; } + @Nullable private Object findFirstElement(String s) { - String _s = s.trim(); - Object[] elements = getAllElements(); - for (Object element : elements) { + final String _s = s.trim(); + for (ListIterator it = getElementIterator(0); it.hasNext();) { + final Object element = it.next(); if (isMatchingElement(element, _s)) return element; } return null; } + @Nullable private Object findLastElement(String s) { - String _s = s.trim(); - Object[] elements = getAllElements(); - for (int i = elements.length - 1; i >= 0; i--) { - Object element = elements[i]; + final String _s = s.trim(); + for (ListIterator it = getElementIterator(-1); it.hasPrevious();) { + final Object element = it.previous(); if (isMatchingElement(element, _s)) return element; } return null; @@ -279,6 +305,7 @@ public abstract class SpeedSearchBase { return true; } + @Nullable public String getEnteredPrefix() { return mySearchPopup != null ? mySearchPopup.mySearchField.getText() : null; } diff --git a/platform/platform-impl/src/com/intellij/ui/TableSpeedSearch.java b/platform/platform-impl/src/com/intellij/ui/TableSpeedSearch.java new file mode 100644 index 000000000000..dae9ddfe2a4f --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/TableSpeedSearch.java @@ -0,0 +1,131 @@ +/* + * Copyright 2000-2010 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.ui; + +import com.intellij.util.containers.Convertor; + +import javax.swing.*; +import javax.swing.table.TableModel; +import java.util.ListIterator; + +public class TableSpeedSearch extends SpeedSearchBase { + private static final Convertor TO_STRING = new Convertor() { + public String convert(Object object) { + return object == null? "" : object.toString(); + } + }; + private final Convertor myToStringConvertor; + + public TableSpeedSearch(JTable table, Convertor toStringConvertor) { + super(table); + myToStringConvertor = toStringConvertor; + } + + public TableSpeedSearch(JTable table) { + this(table, TO_STRING); + } + + + protected boolean isSpeedSearchEnabled() { + return !getComponent().isEditing() && super.isSpeedSearchEnabled(); + } + + @Override + protected ListIterator getElementIterator(int startingIndex) { + return new MyListIterator(startingIndex); + } + + protected void selectElement(Object element, String selectedText) { + final int index = ((Integer)element).intValue(); + final TableModel model = myComponent.getModel(); + final int row = index / model.getColumnCount(); + final int col = index % model.getColumnCount(); + myComponent.getSelectionModel().setSelectionInterval(row, row); + myComponent.getColumnModel().getSelectionModel().setSelectionInterval(col, col); + TableUtil.scrollSelectionToVisible(myComponent); + } + + protected int getSelectedIndex() { + final int row = myComponent.getSelectedRow(); + final int col = myComponent.getSelectedColumn(); + return row > -1 && col > -1? row * myComponent.getModel().getColumnCount() + col : -1; + } + + protected Object[] getAllElements() { + throw new AssertionError("Not Implemented"); + } + + protected String getElementText(Object element) { + final int index = ((Integer)element).intValue(); + final TableModel model = myComponent.getModel(); + final Object value = model.getValueAt(index / model.getColumnCount(), index % model.getColumnCount()); + String string = myToStringConvertor.convert(value); + if (string == null) return TO_STRING.convert(value); + return string; + } + + private class MyListIterator implements ListIterator { + + private int myCursor; + + public MyListIterator(int startingIndex) { + final int total = getTotal(); + myCursor = startingIndex < 0? total : startingIndex; + } + + private int getTotal() { + final TableModel tableModel = myComponent.getModel(); + return tableModel.getRowCount() * tableModel.getColumnCount(); + } + + public boolean hasNext() { + return myCursor < getTotal(); + } + + public Object next() { + return myCursor++; + } + + public boolean hasPrevious() { + return myCursor > 0; + } + + public Object previous() { + return (myCursor--) - 1; + } + + public int nextIndex() { + return myCursor; + } + + public int previousIndex() { + return myCursor - 1; + } + + public void remove() { + throw new AssertionError("Not Implemented"); + } + + public void set(Object o) { + throw new AssertionError("Not Implemented"); + } + + public void add(Object o) { + throw new AssertionError("Not Implemented"); + } + } +} diff --git a/platform/platform-impl/testSrc/com/intellij/ide/util/treeView/TreeUiTest.java b/platform/platform-impl/testSrc/com/intellij/ide/util/treeView/TreeUiTest.java index 0d8674b00bba..7a865e50781d 100644 --- a/platform/platform-impl/testSrc/com/intellij/ide/util/treeView/TreeUiTest.java +++ b/platform/platform-impl/testSrc/com/intellij/ide/util/treeView/TreeUiTest.java @@ -971,6 +971,55 @@ public class TreeUiTest extends AbstractTreeBuilderTest { } + public void testQueryStructureIsAlwaysShowsPlus() throws Exception { + buildStructure(myRoot); + myAlwaysShowPlus.add(new NodeElement("jetbrains")); + myAlwaysShowPlus.add(new NodeElement("ide")); + + expand(getPath("/")); + assertTree("-/\n" + + " +com\n" + + " +jetbrains\n" + + " +org\n" + + " +xunit\n"); + + assertUpdates("/: update (2) getChildren\n" + + "com: update getChildren\n" + + "eclipse: update\n" + + "intellij: update\n" + + "jetbrains: update\n" + + "org: update getChildren\n" + + "runner: update\n" + + "xunit: update getChildren"); + + expand(getPath("jetbrains")); + expand(getPath("fabrique")); + + assertTree("-/\n" + + " +com\n" + + " -jetbrains\n" + + " -fabrique\n" + + " +ide\n" + + " +org\n" + + " +xunit\n"); + + assertUpdates("fabrique: update getChildren\n" + + "ide: update\n" + + "jetbrains: update getChildren"); + + + expand(getPath("ide")); + assertTree("-/\n" + + " +com\n" + + " -jetbrains\n" + + " -fabrique\n" + + " ide\n" + + " +org\n" + + " +xunit\n"); + + assertUpdates("ide: update getChildren"); + } + public void testQueryStructureIsAlwaysLeaf() throws Exception { buildStructure(myRoot); myStructure.addLeaf(new NodeElement("openapi")); diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index 83298e126d55..8dde553eafd9 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -57,10 +57,13 @@ editbox.keep.blanklines.in.declarations=In declarations: editbox.keep.blanklines.in.code=In code: editbox.keep.blanklines.before.rbrace=Before '}': title.preview=Preview -listbox.members.order.fields=Fields -listbox.members.order.methods=Methods +listbox.members.order.fields=Instance fields +listbox.members.order.static.fields=Static fields +listbox.members.order.methods=Instance methods +listbox.members.order.static.methods=Static methods listbox.members.order.constructors=Constructors listbox.members.order.inner.classes=Inner classes +listbox.members.order.inner.static.classes=Static inner classes title.naming.final.modifier=Final modifier checkbox.make.generated.parameters.final=Make generated parameters final checkbox.make.generated.local.variables.final=Make generated local variables final diff --git a/platform/platform-resources-en/src/messages/KeyMapBundle.properties b/platform/platform-resources-en/src/messages/KeyMapBundle.properties index adb702a98882..12e35efa20a2 100644 --- a/platform/platform-resources-en/src/messages/KeyMapBundle.properties +++ b/platform/platform-resources-en/src/messages/KeyMapBundle.properties @@ -51,7 +51,7 @@ add.keyboard.shortcut.button=Add &Keyboard Shortcut... add.mouse.shortcut.button=Add &Mouse Shortcut... remove.shortcut.button=&Remove -conflict.shortcut.dialog.message=The shortcut is already assigned to other actions.\ +conflict.shortcut.dialog.message=The shortcut is already assigned to other actions. \ Do you want to remove other assignments? conflict.shortcut.dialog.title=Warning conflict.shortcut.dialog.remove.button=Remove @@ -83,7 +83,7 @@ quick.list.panel.add.separator.button=Add Separator quick.list.panel.description.label=Description quick.list.panel.display.name.label=Display name -#0 - modifiers (with + for wingows or empty str), 1 - button num (1 - left, 2 - center, 3 - right 0 - no button) +#0 - modifiers (with + for windows or empty str), 1 - button num (1 - left, 2 - center, 3 - right 0 - no button) mouse.click.shortcut.text={0}Button{1} Click mouse.double.click.shortcut.text={0}Button{1} Double-Click configuration.all.keymaps.should.have.unique.names.error.message=All keymaps should have unique names diff --git a/platform/platform-resources-en/src/messages/SMTestsRunnerBundle.properties b/platform/platform-resources-en/src/messages/SMTestsRunnerBundle.properties index 74f3c5c264cd..de48609766ea 100644 --- a/platform/platform-resources-en/src/messages/SMTestsRunnerBundle.properties +++ b/platform/platform-resources-en/src/messages/SMTestsRunnerBundle.properties @@ -13,6 +13,7 @@ sm.test.runner.ui.tests.tree.presentation.labels.instantiating.tests=Instantiati sm.test.runner.ui.tests.tree.presentation.labels.not.test.results=No Test Results sm.test.runner.ui.tests.tree.presentation.labels.was.terminated=Terminated sm.test.runner.ui.tests.tree.presentation.labels.no.tests.were.found=No tests were found +sm.test.runner.ui.tests.tree.presentation.labels.no.tests.were.found.with.errors=No tests were found. Errors occurred sm.test.runner.ui.tests.tree.presentation.labels.all.tests.passed=All Tests Passed sm.test.runner.ui.tabs.statistics.columns.test.title=Test @@ -24,6 +25,7 @@ sm.test.runner.ui.tabs.statistics.columns.duration.not.run= sm.test.runner.ui.tabs.statistics.columns.duration.prefix.running=RUNNING sm.test.runner.ui.tabs.statistics.columns.duration.prefix.terminated=TERMINATED sm.test.runner.ui.tabs.statistics.columns.results.title=Results +sm.test.runner.ui.tabs.statistics.columns.results.undefined= sm.test.runner.ui.tabs.statistics.columns.results.count.msg.failed=F:{0} sm.test.runner.ui.tabs.statistics.columns.results.count.msg.errors=E:{0} sm.test.runner.ui.tabs.statistics.columns.results.count.msg.passed=P:{0} @@ -44,6 +46,10 @@ sm.test.runner.states.suite.is.empty=Empty test suite. sm.test.runner.states.test.is.ignored=Test ignored. sm.test.runner.notifications.tests.passed=Tests passed +sm.test.runner.notifications.tests.passed.with.errors=Tests passed with errors sm.test.runner.notifications.tests.failed=Tests failed +sm.test.runner.notifications.tests.failed.with.errors=Tests failed with errors sm.test.runner.notifications.tests.skipped=Tests skipped +sm.test.runner.notifications.tests.skipped.with.errors=Tests skipped with errors sm.test.runner.notifications.tests.not.run=Tests were not started +sm.test.runner.notifications.tests.not.run.with.errors=Tests were not started with errors. Errors occurred diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index 3d7f6bf339da..b93e4875390f 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -37,6 +37,8 @@ + + diff --git a/platform/platform-resources/src/idea/Keymap_MacClassic.xml b/platform/platform-resources/src/idea/Keymap_MacClassic.xml index 09746c8664f9..3b4b8c3e1c1e 100644 --- a/platform/platform-resources/src/idea/Keymap_MacClassic.xml +++ b/platform/platform-resources/src/idea/Keymap_MacClassic.xml @@ -5,23 +5,6 @@ - - - - - - - - - - - - - - - - - diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index a28eb65de246..e68bdf9531f9 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -1,5 +1,14 @@ + + + + + + + + + @@ -98,14 +107,6 @@ - - - - - - - - @@ -404,6 +405,12 @@ + + + + + + diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java index 635def2a8ec5..7fa143269bd9 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java @@ -17,6 +17,7 @@ package com.intellij.execution.testframework.sm.runner; import com.intellij.openapi.Disposable; import com.intellij.openapi.util.Key; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -41,6 +42,7 @@ public interface GeneralTestEventsProcessor extends Disposable { void onSuiteFinished(final String suiteName); void onUncapturedOutput(final String text, final Key outputType); + void onError(@NotNull final String localizedMessage, @Nullable final String stackTrace); // Custom progress statistics diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralToSMTRunnerEventsConvertor.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralToSMTRunnerEventsConvertor.java index e3741b79f8c3..55a2a63d3439 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralToSMTRunnerEventsConvertor.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralToSMTRunnerEventsConvertor.java @@ -175,17 +175,7 @@ public class GeneralToSMTRunnerEventsConvertor implements GeneralTestEventsProce public void onUncapturedOutput(final String text, final Key outputType) { SMRunnerUtil.addToInvokeLater(new Runnable() { public void run() { - //if we can locate test - we will send outout to it, otherwise to current test suite - final SMTestProxy currentProxy; - if (myRunningTestsFullNameToProxy.size() == 1) { - //current test - currentProxy = myRunningTestsFullNameToProxy.values().iterator().next(); - } else { - //current suite - // - // ProcessHandler can fire output available event before processStarted event - currentProxy = mySuitesStack.isEmpty() ? myTestsRootNode : getCurrentSuite(); - } + final SMTestProxy currentProxy = findCurrentTestOrSuite(); if (ProcessOutputTypes.STDERR.equals(outputType)) { currentProxy.addStdErr(text); @@ -198,6 +188,16 @@ public class GeneralToSMTRunnerEventsConvertor implements GeneralTestEventsProce }); } + public void onError(@NotNull final String localizedMessage, + @Nullable final String stackTrace) { + SMRunnerUtil.addToInvokeLater(new Runnable() { + public void run() { + final SMTestProxy currentProxy = findCurrentTestOrSuite(); + currentProxy.addError(localizedMessage, stackTrace); + } + }); + } + public void onCustomProgressTestsCategory(@Nullable final String categoryName, final int testCount) { SMRunnerUtil.addToInvokeLater(new Runnable() { @@ -455,4 +455,20 @@ public class GeneralToSMTRunnerEventsConvertor implements GeneralTestEventsProce } }); } + + + private SMTestProxy findCurrentTestOrSuite() { + //if we can locate test - we will send output to it, otherwise to current test suite + final SMTestProxy currentProxy; + if (myRunningTestsFullNameToProxy.size() == 1) { + //current test + currentProxy = myRunningTestsFullNameToProxy.values().iterator().next(); + } else { + //current suite + // + // ProcessHandler can fire output available event before processStarted event + currentProxy = mySuitesStack.isEmpty() ? myTestsRootNode : getCurrentSuite(); + } + return currentProxy; + } } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/OutputToGeneralTestEventsConverter.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/OutputToGeneralTestEventsConverter.java index 39cf6df8043d..1704f6e35bf1 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/OutputToGeneralTestEventsConverter.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/OutputToGeneralTestEventsConverter.java @@ -78,7 +78,7 @@ public class OutputToGeneralTestEventsConverter implements ProcessOutputConsumer public void process(final String text, final Key outputType) { if (outputType != ProcessOutputTypes.STDERR && outputType != ProcessOutputTypes.SYSTEM) { - // we check for consistensy only std output + // we check for consistently only std output // because all events must be send to stdout processStdOutConsistently(text, outputType); } else { @@ -268,6 +268,16 @@ public class OutputToGeneralTestEventsConverter implements ProcessOutputConsumer } } + private void fireOnErrorMsg(@NotNull final String localizedMessage, + @Nullable final String stackTrace) { + + // local variable is used to prevent concurrent modification + final GeneralTestEventsProcessor processor = myProcessor; + if (processor != null) { + processor.onError(localizedMessage, stackTrace); + } + } + private class MyServiceMessageVisitor extends DefaultServiceMessageVisitor { @NonNls public static final String KEY_TESTS_COUNT = "testCount"; @NonNls private static final String ATTR_KEY_TEST_ERROR = "error"; @@ -277,6 +287,13 @@ public class OutputToGeneralTestEventsConverter implements ProcessOutputConsumer @NonNls private static final String ATTR_KEY_LOCATION_URL_OLD = "location"; @NonNls private static final String ATTR_KEY_STACKTRACE_DETAILS = "details"; + @NonNls private static final String MESSAGE = "message"; + @NonNls private static final String ATTR_KEY_STATUS = "status"; + @NonNls private static final String ATTR_VALUE_STATUS_ERROR = "ERROR"; + @NonNls private static final String ATTR_VALUE_STATUS_WARNING = "WARNING"; + @NonNls private static final String ATTR_KEY_TEXT = "text"; + @NonNls private static final String ATTR_KEY_ERROR_DETAILS = "errorDetails"; + @NonNls public static final String CUSTOM_STATUS = "customProgressStatus"; @NonNls private static final String ATTR_KEY_TEST_TYPE = "type"; @NonNls private static final String ATTR_KEY_TESTS_CATEGORY = "testsCategory"; @@ -384,7 +401,32 @@ public class OutputToGeneralTestEventsConverter implements ProcessOutputConsumer processTestCountInSuite(msg); } else if (CUSTOM_STATUS.equals(name)) { processCustomStatus(msg); - } else { + } else if (MESSAGE.equals(name)) { + final Map msgAttrs = msg.getAttributes(); + + final String text = msgAttrs.get(ATTR_KEY_TEXT); + if (!StringUtil.isEmpty(text)){ + // msg status + final String status = msgAttrs.get(ATTR_KEY_STATUS); + if (status.equals(ATTR_VALUE_STATUS_ERROR)) { + // error msg + + final String stackTrace = msgAttrs.get(ATTR_KEY_ERROR_DETAILS); + fireOnErrorMsg(text, stackTrace); + } else if (status.equals(ATTR_VALUE_STATUS_WARNING)) { + // warning msg + + // let's show warning via stderr + fireOnUncapturedOutput(text, ProcessOutputTypes.STDERR); + } else { + // some other text + + // we cannot pass output type here but it is a service message + // let's think that is was stdout + fireOnUncapturedOutput(text, ProcessOutputTypes.STDOUT); + } + } + } else { //Do nothing } } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java index 8ffba72416ff..76341de59ea9 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java @@ -50,7 +50,8 @@ public class SMTestProxy extends CompositePrintable implements PrintableTestProx private Integer myDuration = null; // duration is unknown @Nullable private final String myLocationUrl; private boolean myDurationIsCached = false; // is used for separating unknown and unset duration - + private boolean myHasErrors = false; + private boolean myHasErrorsCached = false; private Printer myPrinter = Printer.DEAF; @@ -88,6 +89,35 @@ public class SMTestProxy extends CompositePrintable implements PrintableTestProx return myState.getMagnitude(); } + public boolean hasErrors() { + // if already cached + if (myHasErrorsCached) { + return myHasErrors; + } + + final boolean canCacheErrors = !myState.isInProgress(); + // calculate + final boolean hasErrors = calcHasErrors(); + if (canCacheErrors) { + myHasErrors = hasErrors; + myHasErrorsCached = true; + } + return hasErrors; + } + + private boolean calcHasErrors() { + if (myHasErrors) { + return true; + } + + for (SMTestProxy child : getChildren()) { + if (child.hasErrors()) { + return true; + } + } + return false; + } + public boolean isLeaf() { return myChildren == null || myChildren.isEmpty(); } @@ -227,7 +257,7 @@ public class SMTestProxy extends CompositePrintable implements PrintableTestProx return; } - // Not allow to diractly set duration for suites. + // Not allow to directly set duration for suites. // It should be the sum of children. This requirement is only // for safety of current model and may be changed LOG.warn("Unsupported operation"); @@ -242,7 +272,7 @@ public class SMTestProxy extends CompositePrintable implements PrintableTestProx if (!isSuite()) { // if isn't in other finished state (ignored, failed or passed) - myState = TestPassedState.INSTACE; + myState = TestPassedState.INSTANCE; } else { //Test Suite myState = determineSuiteStateOnFinished(); @@ -347,6 +377,19 @@ public class SMTestProxy extends CompositePrintable implements PrintableTestProx }); } + public void addError(final String output, + @Nullable final String stackTrace) { + myHasErrors = true; + addLast(new Printable() { + public void printOn(final Printer printer) { + final String errorText = TestFailedState.buildErrorPresentationText(output, stackTrace); + LOG.assertTrue(errorText != null); + + TestFailedState.printError(printer, errorText); + } + }); + } + public void addSystemOutput(final String output) { addLast(new Printable() { public void printOn(final Printer printer) { diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/NotRunState.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/NotRunState.java index e7fd0d2f42cd..7cbbc093f452 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/NotRunState.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/NotRunState.java @@ -37,7 +37,7 @@ public class NotRunState extends AbstractState { return false; } - //TODO[romeo] if wan't run is it deffect or not? May be move it to settings + //TODO[romeo] if hasn't run is it defect or not? May be move it to settings public boolean isDefect() { return false; } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/SuiteInProgressState.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/SuiteInProgressState.java index 7b3a6c399ff7..d428020557fe 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/SuiteInProgressState.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/SuiteInProgressState.java @@ -32,7 +32,7 @@ public class SuiteInProgressState extends TestInProgressState { } ///** - // * If any of child failed proxy also is deffect + // * If any of child failed proxy also is defect // * @return // */ @Override diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestFailedState.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestFailedState.java index a3c96c4ba8e9..4c6a5602c4f7 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestFailedState.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestFailedState.java @@ -19,6 +19,8 @@ import com.intellij.execution.testframework.Printer; import com.intellij.execution.testframework.ui.PrintableTestProxy; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author Roman Chernyatchik @@ -26,14 +28,28 @@ import com.intellij.openapi.util.text.StringUtil; public class TestFailedState extends AbstractState { private final String myPresentationText; - public TestFailedState(final String localizedMessage, final String stackTrace) { + public TestFailedState(@Nullable final String localizedMessage, + @Nullable final String stackTrace) { + myPresentationText = buildErrorPresentationText(localizedMessage, stackTrace); + } + + @Nullable + public static String buildErrorPresentationText(@Nullable final String localizedMessage, + @Nullable final String stackTrace) { final String text = (StringUtil.isEmptyOrSpaces(localizedMessage) ? "" : localizedMessage + PrintableTestProxy.NEW_LINE) + (StringUtil.isEmptyOrSpaces(stackTrace) ? "" : stackTrace + PrintableTestProxy.NEW_LINE); - myPresentationText = StringUtil.isEmptyOrSpaces(text) ? null : text; + return StringUtil.isEmptyOrSpaces(text) ? null : text; + } + + public static void printError(@NotNull final Printer printer, + @NotNull final String errorPresentationText) { + printer.print(PrintableTestProxy.NEW_LINE, ConsoleViewContentType.ERROR_OUTPUT); + printer.mark(); + printer.print(errorPresentationText, ConsoleViewContentType.ERROR_OUTPUT); } @Override @@ -41,12 +57,11 @@ public class TestFailedState extends AbstractState { super.printOn(printer); if (myPresentationText != null) { - printer.print(PrintableTestProxy.NEW_LINE, ConsoleViewContentType.ERROR_OUTPUT); - printer.mark(); - printer.print(myPresentationText, ConsoleViewContentType.ERROR_OUTPUT); + printError(printer, myPresentationText); } } + public boolean isDefect() { return true; } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestPassedState.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestPassedState.java index 7c7bb069dded..beb23403b1e1 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestPassedState.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestPassedState.java @@ -21,7 +21,7 @@ package com.intellij.execution.testframework.sm.runner.states; public class TestPassedState extends AbstractState { //This state is common for all instances and doesn't contains //instance-specific information - public static final TestPassedState INSTACE = new TestPassedState(); + public static final TestPassedState INSTANCE = new TestPassedState(); private TestPassedState() { } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestStateInfo.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestStateInfo.java index 9580fc888228..e3c58ff1bcfe 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestStateInfo.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestStateInfo.java @@ -69,21 +69,21 @@ public interface TestStateInfo { IGNORED_INDEX(5, 2, SMTestsRunnerBundle.message("sm.test.runner.magnitude.ignored.failed.title")), FAILED_INDEX(6, 4, SMTestsRunnerBundle.message("sm.test.runner.magnitude.assertion.failed.title")), ERROR_INDEX(8, 5, SMTestsRunnerBundle.message("sm.test.runner.magnitude.testerror.title")), - PASSED_INDEX(COMPLETE_INDEX.getValue(), COMPLETE_INDEX.getSortWeitht(), SMTestsRunnerBundle.message("sm.test.runner.magnitude.passed.title")); + PASSED_INDEX(COMPLETE_INDEX.getValue(), COMPLETE_INDEX.getSortWeight(), SMTestsRunnerBundle.message("sm.test.runner.magnitude.passed.title")); private final int myValue; - private final int mySortWeitht; + private final int mySortWeight; private final String myTitle; /** * @param value Some magic parameter from legal - * @param sortWeitht Weight for sort comparator + * @param sortWeight Weight for sort comparator * @param title Title */ - Magnitude(final int value, final int sortWeitht, final String title) { + Magnitude(final int value, final int sortWeight, final String title) { myValue = value; myTitle = title; - mySortWeitht = sortWeitht; + mySortWeight = sortWeight; } public int getValue() { @@ -94,8 +94,8 @@ public interface TestStateInfo { return myTitle; } - public int getSortWeitht() { - return mySortWeitht; + public int getSortWeight() { + return mySortWeight; } } } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMPoolOfTestIcons.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMPoolOfTestIcons.java new file mode 100644 index 000000000000..eeceb9ccfccd --- /dev/null +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMPoolOfTestIcons.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2010 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.execution.testframework.sm.runner.ui; + +import com.intellij.execution.testframework.PoolOfTestIcons; +import com.intellij.execution.testframework.ui.TestsProgressAnimator; +import com.intellij.openapi.util.IconLoader; +import com.intellij.ui.LayeredIcon; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +/** + * @author Roman.Chernyatchik + */ +public class SMPoolOfTestIcons implements PoolOfTestIcons { + // Error flag icon + private static final Icon ERROR_ICON_MARK = IconLoader.getIcon("/nodes/errorMark.png"); + + public static final Icon SKIPPED_E_ICON = addErrorMarkTo(SKIPPED_ICON); + public static final Icon PASSED_E_ICON = addErrorMarkTo(PASSED_ICON); + public static final Icon FAILED_E_ICON = addErrorMarkTo(FAILED_ICON); + public static final Icon TERMINATED_E_ICON = addErrorMarkTo(TERMINATED_ICON); + public static final Icon IGNORED_E_ICON = addErrorMarkTo(IGNORED_ICON); + + // Test Progress + public static final Icon PAUSED_E_ICON = addErrorMarkTo(TestsProgressAnimator.PAUSED_ICON); + public static final Icon[] FRAMES_E = new Icon[TestsProgressAnimator.FRAMES.length]; + static { + for (int i = 0, length = FRAMES_E.length; i < length; i++){ + FRAMES_E[i] = addErrorMarkTo(TestsProgressAnimator.FRAMES[i]); + } + } + + @NotNull + public static Icon addErrorMarkTo(@NotNull + final Icon baseIcon) { + return new LayeredIcon(baseIcon, ERROR_ICON_MARK); + } +} diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerNotificationsHandler.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerNotificationsHandler.java index 6d76efed1d8c..d13a71b7531e 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerNotificationsHandler.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerNotificationsHandler.java @@ -53,29 +53,35 @@ public class SMTRunnerNotificationsHandler extends SMTRunnerEventsAdapter { switch (magnitude) { case SKIPPED_INDEX: case IGNORED_INDEX: - msg = SMTestsRunnerBundle.message("sm.test.runner.notifications.tests.skipped"); + msg = testsRoot.hasErrors() ? SMTestsRunnerBundle.message("sm.test.runner.notifications.tests.skipped.with.errors") + : SMTestsRunnerBundle.message("sm.test.runner.notifications.tests.skipped"); + type = MessageType.WARNING; break; case NOT_RUN_INDEX: - msg = SMTestsRunnerBundle.message("sm.test.runner.notifications.tests.not.run"); + msg = testsRoot.hasErrors() ? SMTestsRunnerBundle.message("sm.test.runner.notifications.tests.not.run.with.errors") + : SMTestsRunnerBundle.message("sm.test.runner.notifications.tests.not.run"); type = MessageType.WARNING; break; case FAILED_INDEX: case ERROR_INDEX: - msg = SMTestsRunnerBundle.message("sm.test.runner.notifications.tests.failed"); + msg = testsRoot.hasErrors() ? SMTestsRunnerBundle.message("sm.test.runner.notifications.tests.failed.with.errors") + : SMTestsRunnerBundle.message("sm.test.runner.notifications.tests.failed"); type = MessageType.ERROR; break; case COMPLETE_INDEX: if (testsRoot.getChildren().size() == 0) { - msg = SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.no.tests.were.found"); + msg = testsRoot.hasErrors() ? SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.no.tests.were.found.with.errors") + : SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.no.tests.were.found"); type = MessageType.ERROR; break; } // else same as: PASSED_INDEX case PASSED_INDEX: - msg = SMTestsRunnerBundle.message("sm.test.runner.notifications.tests.passed"); + msg = testsRoot.hasErrors() ? SMTestsRunnerBundle.message("sm.test.runner.notifications.tests.passed.with.errors") + : SMTestsRunnerBundle.message("sm.test.runner.notifications.tests.passed"); type = MessageType.INFO; break; diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java index 6134c176baf6..16149d7a4319 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java @@ -491,7 +491,7 @@ public class SMTestRunnerResultsForm extends TestResultsPanel implements TestFra private void updateCountersAndProgressOnTestCount(final int count, final boolean isCustomMessage) { if (!isModeConsistent(isCustomMessage)) return; - //This is for beter support groups of TestSuites + //This is for better support groups of TestSuites //Each group notifies about it's size myTestsTotal += count; updateStatusLabel(); diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtil.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtil.java index f104fc4ae35a..4e3751428df1 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtil.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtil.java @@ -34,6 +34,8 @@ import java.awt.*; import java.util.List; import java.util.Set; +import static com.intellij.execution.testframework.sm.runner.ui.SMPoolOfTestIcons.*; + /** * @author Roman Chernyatchik */ @@ -201,29 +203,37 @@ public class TestsPresentationUtil { } + @Nullable private static Icon getIcon(final SMTestProxy testProxy, final TestConsoleProperties consoleProperties) { final TestStateInfo.Magnitude magnitude = testProxy.getMagnitudeInfo(); + + final boolean hasErrors = testProxy.hasErrors(); + switch (magnitude) { case ERROR_INDEX: - return PoolOfTestIcons.ERROR_ICON; + return ERROR_ICON; case FAILED_INDEX: - return PoolOfTestIcons.FAILED_ICON; + return hasErrors ? FAILED_E_ICON : FAILED_ICON; case IGNORED_INDEX: - return PoolOfTestIcons.IGNORED_ICON; + return hasErrors ? IGNORED_E_ICON : IGNORED_ICON; case NOT_RUN_INDEX: - return PoolOfTestIcons.NOT_RAN; + return NOT_RAN; case COMPLETE_INDEX: case PASSED_INDEX: - return PoolOfTestIcons.PASSED_ICON; + return hasErrors ? PASSED_E_ICON : PASSED_ICON; case RUNNING_INDEX: - return !consoleProperties.isPaused() - ? TestsProgressAnimator.getCurrentFrame() - : TestsProgressAnimator.PAUSED_ICON; + if (consoleProperties.isPaused()) { + return hasErrors ? PAUSED_E_ICON : TestsProgressAnimator.PAUSED_ICON; + } + else { + final int frameIndex = TestsProgressAnimator.getCurrentFrameIndex(); + return hasErrors ? FRAMES_E[frameIndex] : TestsProgressAnimator.FRAMES[frameIndex]; + } case SKIPPED_INDEX: - return PoolOfTestIcons.SKIPPED_ICON; + return hasErrors ? SKIPPED_E_ICON : SKIPPED_ICON; case TERMINATED_INDEX: - return PoolOfTestIcons.TERMINATED_ICON; + return hasErrors ? TERMINATED_E_ICON : TERMINATED_ICON; } return null; } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/statistics/BaseColumn.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/statistics/BaseColumn.java index 9e064906ae33..652c959e23ba 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/statistics/BaseColumn.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/statistics/BaseColumn.java @@ -43,7 +43,7 @@ public abstract class BaseColumn extends ColumnInfo { @Override public void sort(@NotNull final List testProxies) { - //Invariant: comparator should left Total(initally at row = 0) row as uppermost element! + //Invariant: comparator should left Total(initially at row = 0) row as uppermost element! StatisticsTableModel.applySortOperation(testProxies, oldSortFun); } } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/statistics/ColumnResults.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/statistics/ColumnResults.java index 154dfacb3597..b71be34401be 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/statistics/ColumnResults.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/statistics/ColumnResults.java @@ -30,7 +30,7 @@ import java.util.Comparator; * @author Roman Chernyatchik */ public class ColumnResults extends BaseColumn implements Comparator { - @NonNls private static final String UNDERFINED = ""; + @NonNls public static final String UNDEFINED = SMTestsRunnerBundle.message("sm.test.runner.ui.tabs.statistics.columns.results.undefined"); public ColumnResults() { super(SMTestsRunnerBundle.message("sm.test.runner.ui.tabs.statistics.columns.results.title")); @@ -73,10 +73,10 @@ public class ColumnResults extends BaseColumn implements Comparator private int compareTests(final SMTestProxy test1, final SMTestProxy test2) { // Rule1. For tests: NotRun < Ignored, etc < Passed < Failure < Error < Progress < Terminated - final int weitht1 = test1.getMagnitudeInfo().getSortWeitht(); - final int weitht2 = test2.getMagnitudeInfo().getSortWeitht(); + final int weight1 = test1.getMagnitudeInfo().getSortWeight(); + final int weight2 = test2.getMagnitudeInfo().getSortWeight(); - return compareInt(weitht1, weitht2); + return compareInt(weight1, weight2); } private int compareSuites(final SMTestProxy suite1, @@ -117,7 +117,7 @@ public class ColumnResults extends BaseColumn implements Comparator } public String valueOf(final SMTestProxy testProxy) { - return UNDERFINED; + return UNDEFINED; } @Override diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/SMTRunnerConsoleTest.java b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/SMTRunnerConsoleTest.java index 285b64a53cbd..ea0cec21d675 100644 --- a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/SMTRunnerConsoleTest.java +++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/SMTRunnerConsoleTest.java @@ -263,6 +263,68 @@ public class SMTRunnerConsoleTest extends BaseSMTRunnerTestCase { assertAllOutputs(mockPrinter2, "stdout1 ", "stderr1 \nerror msg\nmethod1:1\nmethod2:2\n", ""); } + public void testProcessor_OnErrorMsg() { + final SMTestProxy myTest1 = startTestWithPrinter("my_test"); + + myEventsProcessor.onError("error msg", "method1:1\nmethod2:2"); + myEventsProcessor.onTestOutput("my_test", "stdout1 ", true); + myEventsProcessor.onTestOutput("my_test", "stderr1 ", false); + + assertAllOutputs(myMockResetablePrinter, "stdout1 ", "\nerror msg\nmethod1:1\nmethod2:2\nstderr1 ", ""); + + final MockPrinter mockPrinter1 = new MockPrinter(true); + mockPrinter1.onNewAvailable(myTest1); + assertAllOutputs(mockPrinter1, "stdout1 ", "\n" + + "error msg\n" + + "method1:1\n" + + "method2:2\n" + + "stderr1 ", ""); + myEventsProcessor.onTestFinished("my_test", 1); + myTest1.setFinished(); + + //other output order + final SMTestProxy myTest2 = startTestWithPrinter("my_test2"); + myEventsProcessor.onTestOutput("my_test2", "stdout1 ", true); + myEventsProcessor.onTestOutput("my_test2", "stderr1 ", false); + myEventsProcessor.onError("error msg", "method1:1\nmethod2:2"); + + assertAllOutputs(myMockResetablePrinter, "stdout1 ", "stderr1 \nerror msg\nmethod1:1\nmethod2:2\n", ""); + final MockPrinter mockPrinter2 = new MockPrinter(true); + mockPrinter2.onNewAvailable(myTest2); + assertAllOutputs(mockPrinter2, "stdout1 ", "stderr1 \nerror msg\nmethod1:1\nmethod2:2\n", ""); + } + + public void testProcessor_Suite_OnErrorMsg() { + myEventsProcessor.onError("error msg:root", "method1:1\nmethod2:2"); + + myEventsProcessor.onSuiteStarted("suite", null); + final SMTestProxy suite = myEventsProcessor.getCurrentSuite(); + suite.setPrintLinstener(myMockResetablePrinter); + myEventsProcessor.onError("error msg:suite", "method1:1\nmethod2:2"); + + assertAllOutputs(myMockResetablePrinter, "", "\n" + + "error msg:suite\n" + + "method1:1\n" + + "method2:2\n", ""); + + final MockPrinter mockSuitePrinter = new MockPrinter(true); + mockSuitePrinter.onNewAvailable(suite); + assertAllOutputs(mockSuitePrinter, "", "\n" + + "error msg:suite\n" + + "method1:1\n" + + "method2:2\n", ""); + final MockPrinter mockRootSuitePrinter = new MockPrinter(true); + mockRootSuitePrinter.onNewAvailable(myRootSuite); + assertAllOutputs(mockRootSuitePrinter, "", "\n" + + "error msg:root\n" + + "method1:1\n" + + "method2:2\n" + + "\n" + + "error msg:suite\n" + + "method1:1\n" + + "method2:2\n", ""); + } + public void testProcessor_OnIgnored() { final SMTestProxy myTest1 = startTestWithPrinter("my_test"); diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/SMTestProxyTest.java b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/SMTestProxyTest.java index 93e4a4e5ab3a..ce491c3b5047 100644 --- a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/SMTestProxyTest.java +++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/SMTestProxyTest.java @@ -775,7 +775,7 @@ public class SMTestProxyTest extends BaseSMTRunnerTestCase { assertWeightsOrder(Magnitude.NOT_RUN_INDEX, Magnitude.SKIPPED_INDEX); assertWeightsOrder(Magnitude.SKIPPED_INDEX, Magnitude.IGNORED_INDEX); assertWeightsOrder(Magnitude.IGNORED_INDEX, Magnitude.COMPLETE_INDEX); - assertEquals(Magnitude.COMPLETE_INDEX.getSortWeitht() , Magnitude.PASSED_INDEX.getSortWeitht()); + assertEquals(Magnitude.COMPLETE_INDEX.getSortWeight() , Magnitude.PASSED_INDEX.getSortWeight()); assertWeightsOrder(Magnitude.PASSED_INDEX, Magnitude.FAILED_INDEX); assertWeightsOrder(Magnitude.FAILED_INDEX, Magnitude.ERROR_INDEX); assertWeightsOrder(Magnitude.ERROR_INDEX, Magnitude.TERMINATED_INDEX); @@ -792,6 +792,6 @@ public class SMTestProxyTest extends BaseSMTRunnerTestCase { } protected void assertWeightsOrder(final Magnitude previous, final Magnitude next) { - assertTrue(previous.getSortWeitht() < next.getSortWeitht()); + assertTrue(previous.getSortWeight() < next.getSortWeight()); } } diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java index 421eb1d811b9..4b252144638e 100644 --- a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java +++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java @@ -144,6 +144,18 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { assertEquals(SimpleTextAttributes.REGULAR_ATTRIBUTES, myFragContainer.getAttribsAt(0)); } + public void testFormatTestProxyTest_StartedAndPaused_WithErrors() { + //paused + final MyRenderer pausedRenderer = new MyRenderer(true, myFragContainer = new UITestUtil.FragmentsContainer()); + + mySimpleTest.setStarted(); + mySimpleTest.addError("msg", "stacktrace"); + + TestsPresentationUtil.formatTestProxy(mySimpleTest, pausedRenderer); + + assertEquals(SMPoolOfTestIcons.PAUSED_E_ICON, pausedRenderer.getIcon()); + } + public void testFormatTestProxyTest_Passed() { mySimpleTest.setStarted(); mySimpleTest.setFinished(); @@ -170,6 +182,15 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { assertEquals(PoolOfTestIcons.FAILED_ICON, myRenderer.getIcon()); } + public void testFormatTestProxyTest_Failed_WithErrors() { + mySimpleTest.setStarted(); + mySimpleTest.setTestFailed("", "", false); + mySimpleTest.addError("msg", "stacktrace"); + TestsPresentationUtil.formatTestProxy(mySimpleTest, myRenderer); + + assertEquals(SMPoolOfTestIcons.FAILED_E_ICON, myRenderer.getIcon()); + } + public void testFormatTestProxyTest_Error() { mySimpleTest.setStarted(); mySimpleTest.setTestFailed("", "", true); @@ -185,6 +206,15 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { assertEquals(PoolOfTestIcons.ERROR_ICON, myRenderer.getIcon()); } + public void testFormatTestProxyTest_Error_WithErrors() { + mySimpleTest.setStarted(); + mySimpleTest.setTestFailed("", "", true); + mySimpleTest.addError("msg", "stacktrace"); + TestsPresentationUtil.formatTestProxy(mySimpleTest, myRenderer); + + assertEquals(PoolOfTestIcons.ERROR_ICON, myRenderer.getIcon()); + } + public void testFormatTestProxyTest_Ignored() { mySimpleTest.setStarted(); mySimpleTest.setTestIgnored("", null); @@ -200,6 +230,15 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { assertEquals(PoolOfTestIcons.IGNORED_ICON, myRenderer.getIcon()); } + public void testFormatTestProxyTest_Ignored_WithErrors() { + mySimpleTest.setStarted(); + mySimpleTest.setTestIgnored("", null); + mySimpleTest.addError("msg", "stacktrace"); + TestsPresentationUtil.formatTestProxy(mySimpleTest, myRenderer); + + assertEquals(SMPoolOfTestIcons.IGNORED_E_ICON, myRenderer.getIcon()); + } + public void testFormatTestProxyTest_Terminated() { mySimpleTest.setStarted(); mySimpleTest.setTerminated(); @@ -215,6 +254,15 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { assertEquals(PoolOfTestIcons.TERMINATED_ICON, myRenderer.getIcon()); } + public void testFormatTestProxyTest_WithErrors() { + mySimpleTest.setStarted(); + mySimpleTest.setTerminated(); + mySimpleTest.addError("msg", "stacktrace"); + TestsPresentationUtil.formatTestProxy(mySimpleTest, myRenderer); + + assertEquals(SMPoolOfTestIcons.TERMINATED_E_ICON, myRenderer.getIcon()); + } + public void testFormatRootNodeWithChildren_Started() { mySimpleTest.setStarted(); @@ -251,6 +299,27 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { assertEquals("Test Results:", renderer1.getFragmentsContainer().getTextAt(0)); } + public void testFormatRootNodeWithChildren_Failed_WithErrors() { + final MyRenderer renderer1 = new MyRenderer(false, myFragContainer = new UITestUtil.FragmentsContainer()); + + mySuite.addChild(mySimpleTest); + mySuite.setStarted(); + mySimpleTest.setStarted(); + mySimpleTest.setTestFailed("", "", false); + mySimpleTest.addError("msg", "stacktrace"); + mySimpleTest.setFinished(); + mySuite.setFinished(); + + TestsPresentationUtil.formatRootNodeWithChildren(mySuite, renderer1); + + assertEquals(SMPoolOfTestIcons.FAILED_E_ICON, renderer1.getIcon()); + + final MyRenderer renderer2 = new MyRenderer(false, myFragContainer = new UITestUtil.FragmentsContainer()); + TestsPresentationUtil.formatRootNodeWithChildren(mySuite, renderer2); + mySuite.setFinished(); + assertEquals(SMPoolOfTestIcons.FAILED_E_ICON, renderer1.getIcon()); + } + public void testFormatRootNodeWithChildren_Error() { final MyRenderer renderer1 = new MyRenderer(false, myFragContainer = new UITestUtil.FragmentsContainer()); @@ -258,6 +327,7 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { mySuite.setStarted(); mySimpleTest.setStarted(); mySimpleTest.setTestFailed("", "", true); + mySimpleTest.addError("msg", "stacktrace"); mySimpleTest.setFinished(); mySuite.setFinished(); @@ -301,6 +371,27 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { assertEquals("Test Results:", renderer1.getFragmentsContainer().getTextAt(0)); } + public void testFormatRootNodeWithChildren_Ignored_WithErrors() { + final MyRenderer renderer1 = new MyRenderer(false, myFragContainer = new UITestUtil.FragmentsContainer()); + + mySuite.addChild(mySimpleTest); + mySuite.setStarted(); + mySimpleTest.setStarted(); + mySimpleTest.setTestIgnored("", null); + mySimpleTest.addError("msg", "stacktrace"); + mySimpleTest.setFinished(); + mySuite.setFinished(); + + TestsPresentationUtil.formatRootNodeWithChildren(mySuite, renderer1); + + assertEquals(SMPoolOfTestIcons.IGNORED_E_ICON, renderer1.getIcon()); + + final MyRenderer renderer2 = new MyRenderer(false, myFragContainer = new UITestUtil.FragmentsContainer()); + TestsPresentationUtil.formatRootNodeWithChildren(mySuite, renderer2); + mySuite.setFinished(); + assertEquals(SMPoolOfTestIcons.IGNORED_E_ICON, renderer1.getIcon()); + } + public void testFormatRootNodeWithChildren_Passed() { mySuite.addChild(mySimpleTest); mySuite.setStarted(); @@ -316,6 +407,19 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { assertEquals(SimpleTextAttributes.REGULAR_ATTRIBUTES, myRenderer.getFragmentsContainer().getAttribsAt(0)); } + public void testFormatRootNodeWithChildren_Passed_WithErrors() { + mySuite.addChild(mySimpleTest); + mySuite.setStarted(); + mySimpleTest.setStarted(); + mySimpleTest.addError("msg", "stacktrace"); + mySimpleTest.setFinished(); + mySuite.setFinished(); + + TestsPresentationUtil.formatRootNodeWithChildren(mySuite, myRenderer); + + assertEquals(SMPoolOfTestIcons.PASSED_E_ICON, myRenderer.getIcon()); + } + public void testFormatRootNodeWithChildren_Terminated() { mySuite.addChild(mySimpleTest); mySuite.setStarted(); @@ -331,6 +435,19 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { assertEquals(SimpleTextAttributes.REGULAR_ATTRIBUTES, myFragContainer.getAttribsAt(0)); } + public void testFormatRootNodeWithChildren_Terminated_WithErrors() { + mySuite.addChild(mySimpleTest); + mySuite.setStarted(); + mySimpleTest.setStarted(); + mySimpleTest.addError("msg", "stacktrace"); + mySimpleTest.setFinished(); + mySuite.setTerminated(); + // terminated + TestsPresentationUtil.formatRootNodeWithChildren(mySuite, myRenderer); + + assertEquals(SMPoolOfTestIcons.TERMINATED_E_ICON, myRenderer.getIcon()); + } + public void testFormatRootNodeWithChildren_TerminatedAndFinished() { mySuite.addChild(mySimpleTest); mySuite.setStarted(); @@ -348,6 +465,25 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { assertEquals(SimpleTextAttributes.REGULAR_ATTRIBUTES, myFragContainer.getAttribsAt(0)); } + public void testFormatRootNodeWithChildren_Passed_StartShutdownErrors() { + final MyRenderer renderer1 = new MyRenderer(false, myFragContainer = new UITestUtil.FragmentsContainer()); + + mySuite.addChild(mySimpleTest); + mySuite.setStarted(); + mySuite.addError("msg1", "stacktrace1"); + mySimpleTest.setStarted(); + mySimpleTest.setFinished(); + mySuite.addError("msg2", "stacktrace2"); + mySuite.setFinished(); + + TestsPresentationUtil.formatRootNodeWithChildren(mySuite, renderer1); + assertEquals(SMPoolOfTestIcons.PASSED_E_ICON, renderer1.getIcon()); + + final MyRenderer renderer2 = new MyRenderer(false, myFragContainer = new UITestUtil.FragmentsContainer()); + TestsPresentationUtil.formatRootNodeWithChildren(mySimpleTest, renderer2); + assertEquals(SMPoolOfTestIcons.PASSED_ICON, renderer2.getIcon()); + } + public void testFormatRootNodeWithoutChildren() { TestsPresentationUtil.formatRootNodeWithoutChildren(mySimpleTest, myRenderer); diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/statistics/ColumnResultsTest.java b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/statistics/ColumnResultsTest.java index 48c1b8e5c34d..675c56dd7e6e 100644 --- a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/statistics/ColumnResultsTest.java +++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/statistics/ColumnResultsTest.java @@ -1,4 +1,4 @@ -/* + /* * Copyright 2000-2009 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -86,26 +86,26 @@ public class ColumnResultsTest extends BaseColumnRenderingTest { } public void testValueOf_Test() { - assertEquals("", myColumn.valueOf(mySimpleTest)); + assertEquals(ColumnResults.UNDEFINED, myColumn.valueOf(mySimpleTest)); mySimpleTest.setStarted(); - assertEquals("", myColumn.valueOf(mySimpleTest)); + assertEquals(ColumnResults.UNDEFINED, myColumn.valueOf(mySimpleTest)); mySimpleTest.setFinished(); - assertEquals("", myColumn.valueOf(mySimpleTest)); + assertEquals(ColumnResults.UNDEFINED, myColumn.valueOf(mySimpleTest)); } public void testValueOf_Suite() { - assertEquals("", myColumn.valueOf(mySuite)); + assertEquals(ColumnResults.UNDEFINED, myColumn.valueOf(mySuite)); mySuite.setStarted(); - assertEquals("", myColumn.valueOf(mySuite)); + assertEquals(ColumnResults.UNDEFINED, myColumn.valueOf(mySuite)); createTestProxy(mySuite); - assertEquals("", myColumn.valueOf(mySuite)); + assertEquals(ColumnResults.UNDEFINED, myColumn.valueOf(mySuite)); mySuite.setFinished(); - assertEquals("", myColumn.valueOf(mySuite)); + assertEquals(ColumnResults.UNDEFINED, myColumn.valueOf(mySuite)); } public void testPresentation_SuiteNotRun() { diff --git a/platform/testFramework/src/com/intellij/TestAll.java b/platform/testFramework/src/com/intellij/TestAll.java index 26888d1a67f8..4b4c6a0fb316 100644 --- a/platform/testFramework/src/com/intellij/TestAll.java +++ b/platform/testFramework/src/com/intellij/TestAll.java @@ -87,7 +87,7 @@ public class TestAll implements Test { if ((ourMode & START_GUARD) != 0) { Thread timeAndMemoryGuard = new Thread() { public void run() { - System.out.println("Starting Time and Memory Guard"); + log("Starting Time and Memory Guard"); while (true) { try { try { @@ -104,7 +104,7 @@ public class TestAll implements Test { if (!mySavingMemorySnapshot) { if (secondsSpent > PlatformTestCase.ourTestTime * myLastTestTestMethodCount) { UsefulTestCase.printThreadDump(); - System.out.println("Interrupting current Test (out of time)! Test class: "+ myLastTestClass +" Seconds spent = " + secondsSpent); + log("Interrupting current Test (out of time)! Test class: "+ myLastTestClass +" Seconds spent = " + secondsSpent); myInterruptedByOutOfTime = true; if (currentThread != null) { currentThread.interrupt(); @@ -122,7 +122,7 @@ public class TestAll implements Test { e.printStackTrace(); } } - System.out.println("Time and Memory Guard finished."); + log("Time and Memory Guard finished."); } }; timeAndMemoryGuard.setDaemon(true); @@ -201,8 +201,7 @@ public class TestAll implements Test { } } - System.out.println("\nRunning " + testCaseClass.getName()); - LOG.info("Running " + testCaseClass.getName()); + log("\nRunning " + testCaseClass.getName()); final Test test = getTest(testCaseClass); if (test == null) return; @@ -253,10 +252,10 @@ public class TestAll implements Test { if ((ourMode & SAVE_MEMORY_SNAPSHOT) != 0) { try { mySavingMemorySnapshot = true; - System.out.println("OutOfMemoryError detected. Saving memory snapshot started"); + log("OutOfMemoryError detected. Saving memory snapshot started"); } finally { - System.out.println("Saving memory snapshot finished"); + log("Saving memory snapshot finished"); mySavingMemorySnapshot = false; } } @@ -273,7 +272,7 @@ public class TestAll implements Test { tryGc(5); possibleOutOfMemoryError = possibleOutOfMemory(neededMemory); if (possibleOutOfMemoryError) { - System.out.println("OutOfMemoryError: dumping memory"); + log("OutOfMemoryError: dumping memory"); Runtime runtime = Runtime.getRuntime(); long total = runtime.totalMemory(); long free = runtime.freeMemory(); @@ -364,7 +363,11 @@ public class TestAll implements Test { myTestCaseLoader.clearClasses(); } - System.out.println("Number of test classes found: " + myTestCaseLoader.getClasses().size()); + log("Number of test classes found: " + myTestCaseLoader.getClasses().size()); + } + + private static void log(String message) { + TeamCityLogger.info(message); } // [myakovlev] Do not delete - it is for debugging @@ -380,7 +383,7 @@ public class TestAll implements Test { } System.gc(); //long mem = Runtime.getRuntime().totalMemory(); - System.out.println("Runtime.getRuntime().totalMemory() = " + Runtime.getRuntime().totalMemory()); + log("Runtime.getRuntime().totalMemory() = " + Runtime.getRuntime().totalMemory()); } } diff --git a/platform/testFramework/src/com/intellij/mock/MockApplication.java b/platform/testFramework/src/com/intellij/mock/MockApplication.java index ea834c98f34a..b1a6dd7a2c28 100644 --- a/platform/testFramework/src/com/intellij/mock/MockApplication.java +++ b/platform/testFramework/src/com/intellij/mock/MockApplication.java @@ -261,6 +261,10 @@ public class MockApplication extends MockComponentManager implements Application public void assertIsDispatchThread(@Nullable final JComponent component) { } + public void runEdtSafeAction(@NotNull Runnable runnable) { + runnable.run(); + } + public boolean tryRunReadAction(@NotNull Runnable runnable) { return false; } diff --git a/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java index 64d6170f3ec8..6b3460961ece 100644 --- a/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java @@ -16,11 +16,12 @@ package com.intellij.testFramework; import com.intellij.ide.DataManager; -import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.editor.actionSystem.EditorActionManager; import com.intellij.openapi.editor.actionSystem.TypedAction; +import junit.framework.Assert; /** * User: Maxim.Mossienko @@ -49,4 +50,21 @@ public class EditorTestUtil { action.actionPerformed(editor, c, DataManager.getInstance().getDataContext()); } } + + public static void performReferenceCopy(DataContext dataContext) { + ActionManager actionManager = ActionManager.getInstance(); + AnAction action = actionManager.getAction(IdeActions.ACTION_COPY_REFERENCE); + AnActionEvent + event = new AnActionEvent(null, dataContext, "", action.getTemplatePresentation(), + ActionManager.getInstance(), 0); + action.update(event); + Assert.assertTrue(event.getPresentation().isEnabled()); + action.actionPerformed(event); + } + + public static void performPaste(Editor editor) { + EditorActionManager actionManager = EditorActionManager.getInstance(); + EditorActionHandler actionHandler = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_PASTE); + actionHandler.execute(editor, DataManager.getInstance().getDataContext()); + } } diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java index ff7be9f4f218..194268de8996 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java @@ -15,7 +15,7 @@ */ package com.intellij.testFramework; -import com.intellij.ide.DataManager; +import com.intellij.ide.*; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.ide.util.treeView.AbstractTreeStructure; import com.intellij.idea.Bombed; @@ -43,11 +43,15 @@ import junit.framework.AssertionFailedError; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import java.util.*; +import java.awt.*; +import java.awt.event.InvocationEvent; + /** * @author yole @@ -183,6 +187,20 @@ public class PlatformTestUtil { } } + @TestOnly + public static void dispatchAllInvocationEventsInIdeEventQueue() throws InterruptedException { + assert SwingUtilities.isEventDispatchThread() : Thread.currentThread(); + final EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); + while (true) { + AWTEvent event = eventQueue.peekEvent(); + if (event == null) break; + AWTEvent event1 = eventQueue.getNextEvent(); + if (event1 instanceof InvocationEvent) { + IdeEventQueue.getInstance().dispatchEvent(event1); + } + } + } + private static Date raidDate(Bombed bombed) { final Calendar instance = Calendar.getInstance(); instance.set(Calendar.YEAR, bombed.year()); @@ -190,9 +208,8 @@ public class PlatformTestUtil { instance.set(Calendar.DAY_OF_MONTH, bombed.day()); instance.set(Calendar.HOUR_OF_DAY, bombed.time()); instance.set(Calendar.MINUTE, 0); - Date time = instance.getTime(); - return time; + return instance.getTime(); } public static boolean bombExplodes(Bombed bombedAnnotation) { @@ -344,18 +361,22 @@ public class PlatformTestUtil { // For faster machines (expectedOnMyMachine < expected) allow nonlinear performance rating: // just perform better than acceptable expected int percentage = (int)(100.0 * (actual - expectedOnMyMachine) / expectedOnMyMachine); - String failMessage = message + "." + + String logMessage = message + "." + " Operation took " + percentage + "% longer than expected." + " Expected on my machine: " + expectedOnMyMachine + "." + " Actual: " + actual + "." + " Expected on Etalon machine: " + expected + ";" + " Actual on Etalon: " + actual * ETALON_TIMING / Timings.MACHINE_TIMING; - if (actual > expectedOnMyMachine * acceptableChangeFactor && + + if (actual < expectedOnMyMachine) { + TeamCityLogger.info(logMessage); + } + else if (actual > expectedOnMyMachine * acceptableChangeFactor && (expectedOnMyMachine > expected || actual > expected * acceptableChangeFactor)) { - Assert.fail(failMessage); + TeamCityLogger.warning(logMessage); } else { - System.out.println(failMessage); + TeamCityLogger.error(logMessage); } } @@ -383,7 +404,7 @@ public class PlatformTestUtil { System.gc(); System.gc(); System.gc(); - System.out.println("Another epic fail: "+e.getMessage() +"; Attempts remained: "+attempts); + TeamCityLogger.info("Another epic fail: "+e.getMessage() +"; Attempts remained: "+attempts); } } } diff --git a/platform/testFramework/src/com/intellij/testFramework/TeamCityLogger.java b/platform/testFramework/src/com/intellij/testFramework/TeamCityLogger.java new file mode 100644 index 000000000000..4f1ef41e5748 --- /dev/null +++ b/platform/testFramework/src/com/intellij/testFramework/TeamCityLogger.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2010 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. + */ + +/* + * @author max + */ +package com.intellij.testFramework; + +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.io.FileUtil; + +import java.io.File; +import java.io.IOException; + +public class TeamCityLogger { + private static final Logger LOG = Logger.getInstance("#com.intellij.testFramework.TeamCityLogger"); + + private final static boolean isUnderTC = System.getProperty("bootstrap.testcases") != null; + + private TeamCityLogger() {} + + private static File reportFile() { + return new File(PathManager.getHomePath() + "/reports/report.txt"); + } + + public static void info(String message) { + if (isUnderTC) { + tcLog(message, null); + } + else { + LOG.info(message); + } + } + + public static void warning(String message) { + if (isUnderTC) { + tcLog(message, "WARNING"); + } + else { + LOG.warn(message); + } + } + + public static void error(String message) { + if (isUnderTC) { + tcLog(message, "ERROR"); + } + else { + LOG.error(message); + } + } + + private static void tcLog(String message, String level) { + try { + if (level != null) message = level + ": " + message; + FileUtil.appendToFile(reportFile(), message + "\n"); + } + catch (IOException e) { + LOG.error(e); + } + } +} diff --git a/platform/testFramework/src/com/intellij/testFramework/TestDataHighlightingPassFactory.java b/platform/testFramework/src/com/intellij/testFramework/TestDataHighlightingPassFactory.java index 7aac28221f38..0e9cc91cf4c6 100644 --- a/platform/testFramework/src/com/intellij/testFramework/TestDataHighlightingPassFactory.java +++ b/platform/testFramework/src/com/intellij/testFramework/TestDataHighlightingPassFactory.java @@ -40,7 +40,9 @@ public class TestDataHighlightingPassFactory extends AbstractProjectComponent im public static final List SUPPORTED_FILE_TYPES = Arrays.asList( StdFileTypes.JAVA.getDefaultExtension() ); - public static final List SUPPORTED_IN_TEST_DATA_FILE_TYPES = Arrays.asList("js", "php", "css", "html", "xhtml", "jsp", "test", "py"); + public static final List SUPPORTED_IN_TEST_DATA_FILE_TYPES = Arrays.asList( + "js", "php", "css", "html", "xhtml", "jsp", "test", "py", "aj" + ); private static final int MAX_HOPES = 3; private static final String TEST_DATA = "testdata"; diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index 648c9d945c05..6cd2908b3dce 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -381,11 +381,11 @@ public abstract class UsefulTestCase extends TestCase { } public static void assertSize(int expectedSize, final Object[] array) { - assertEquals(expectedSize, array.length); + assertEquals(toString(Arrays.asList(array)), expectedSize, array.length); } public static void assertSize(int expectedSize, final Collection c) { - assertEquals(expectedSize, c.size()); + assertEquals(toString(c), expectedSize, c.size()); } protected T disposeOnTearDown(final T disposable) { diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java index 8f8006d2924c..5207a02eea19 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java @@ -23,10 +23,10 @@ import com.intellij.codeInspection.InspectionProfileEntry; import com.intellij.codeInspection.InspectionToolProvider; import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.ex.InspectionTool; -import com.intellij.find.findUsages.FindUsagesOptions; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.markup.GutterIconRenderer; +import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; @@ -277,6 +277,8 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { Collection findUsages(final PsiElement to) throws Exception; + RangeHighlighter[] testHighlightUsages(String... files); + void moveFile(@NonNls String filePath, @NonNls String to, final String... additionalFiles) throws Exception; /** diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 0146adc33f0d..57df4aa752ec 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -29,6 +29,7 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings; import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInsight.daemon.impl.*; +import com.intellij.codeInsight.highlighting.HighlightUsagesHandler; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler; import com.intellij.codeInsight.lookup.LookupElement; @@ -613,6 +614,13 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig return processor.getResults(); } + public RangeHighlighter[] testHighlightUsages(final String... files) { + configureByFiles(files); + final Editor editor = getEditor(); + HighlightUsagesHandler.invoke(getProject(), editor, getFile()); + return editor.getMarkupModel().getAllHighlighters(); + } + public void moveFile(@NonNls final String filePath, @NonNls final String to, final String... additionalFiles) throws Exception { assertInitialized(); final Project project = myProjectFixture.getProject(); diff --git a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsProgressAnimator.java b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsProgressAnimator.java index ec14bc381c99..147d31912a3a 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsProgressAnimator.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsProgressAnimator.java @@ -46,9 +46,12 @@ public abstract class TestsProgressAnimator implements Runnable, Disposable { FRAMES[i] = TestsUIUtil.loadIcon("testInProgress" + (i + 1)); } + public static int getCurrentFrameIndex() { + return (int) ((System.currentTimeMillis() % MOVIE_TIME) / FRAME_TIME); + } + public static Icon getCurrentFrame() { - final int frameIndex = (int) ((System.currentTimeMillis() % MOVIE_TIME) / FRAME_TIME); - return FRAMES[frameIndex]; + return FRAMES[getCurrentFrameIndex()]; } /** diff --git a/platform/usageView/src/com/intellij/usages/ReadWriteAccessUsageInfo2UsageAdapter.java b/platform/usageView/src/com/intellij/usages/ReadWriteAccessUsageInfo2UsageAdapter.java index d06cf453615d..43770e1d0922 100644 --- a/platform/usageView/src/com/intellij/usages/ReadWriteAccessUsageInfo2UsageAdapter.java +++ b/platform/usageView/src/com/intellij/usages/ReadWriteAccessUsageInfo2UsageAdapter.java @@ -30,16 +30,14 @@ public class ReadWriteAccessUsageInfo2UsageAdapter extends UsageInfo2UsageAdapte super(usageInfo); myAccessedForReading = accessedForReading; myAccessedForWriting = accessedForWriting; - if (myIcon == null) { - if (myAccessedForReading && myAccessedForWriting) { - myIcon = Icons.VARIABLE_RW_ACCESS; - } - else if (myAccessedForWriting) { - myIcon = Icons.VARIABLE_WRITE_ACCESS; // If icon is changed, don't forget to change UTCompositeUsageNode.getIcon(); - } - else if (myAccessedForReading){ - myIcon = Icons.VARIABLE_READ_ACCESS; // If icon is changed, don't forget to change UTCompositeUsageNode.getIcon(); - } + if (myAccessedForReading && myAccessedForWriting) { + myIcon = Icons.VARIABLE_RW_ACCESS; + } + else if (myAccessedForWriting) { + myIcon = Icons.VARIABLE_WRITE_ACCESS; // If icon is changed, don't forget to change UTCompositeUsageNode.getIcon(); + } + else if (myAccessedForReading){ + myIcon = Icons.VARIABLE_READ_ACCESS; // If icon is changed, don't forget to change UTCompositeUsageNode.getIcon(); } } diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageGroupingRuleProviderImpl.java b/platform/usageView/src/com/intellij/usages/impl/UsageGroupingRuleProviderImpl.java index 4bdf2de706b3..840c905822fa 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageGroupingRuleProviderImpl.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageGroupingRuleProviderImpl.java @@ -80,14 +80,10 @@ public class UsageGroupingRuleProviderImpl implements UsageGroupingRuleProvider final GroupByModuleTypeAction groupByModuleTypeAction = new GroupByModuleTypeAction(impl); groupByModuleTypeAction.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_DOWN_MASK)), component); - final GroupByFileStructureAction groupByFileStructureAction = new GroupByFileStructureAction(impl); - groupByFileStructureAction.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_M, - InputEvent.CTRL_DOWN_MASK)), component); - + final GroupByFileStructureAction groupByFileStructureAction = createGroupByFileStructureAction(impl); impl.scheduleDisposeOnClose(new Disposable() { public void dispose() { groupByModuleTypeAction.unregisterCustomShortcutSet(component); - groupByFileStructureAction.unregisterCustomShortcutSet(component); } }); @@ -123,6 +119,20 @@ public class UsageGroupingRuleProviderImpl implements UsageGroupingRuleProvider } } + public static GroupByFileStructureAction createGroupByFileStructureAction(UsageViewImpl impl) { + final JComponent component = impl.getComponent(); + final GroupByFileStructureAction groupByFileStructureAction = new GroupByFileStructureAction(impl); + groupByFileStructureAction.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_M, + InputEvent.CTRL_DOWN_MASK)), component); + + impl.scheduleDisposeOnClose(new Disposable() { + public void dispose() { + groupByFileStructureAction.unregisterCustomShortcutSet(component); + } + }); + return groupByFileStructureAction; + } + private static class GroupByUsageTypeAction extends RuleAction { private GroupByUsageTypeAction(UsageViewImpl view) { super(view, UsageViewBundle.message("action.group.by.usage.type"), IconLoader.getIcon("/ant/filter.png")); //TODO: special icon diff --git a/platform/usageView/src/com/intellij/usages/impl/rules/UsageScopeGroupingRule.java b/platform/usageView/src/com/intellij/usages/impl/rules/UsageScopeGroupingRule.java index 77e667f01aef..91ff84983d54 100644 --- a/platform/usageView/src/com/intellij/usages/impl/rules/UsageScopeGroupingRule.java +++ b/platform/usageView/src/com/intellij/usages/impl/rules/UsageScopeGroupingRule.java @@ -15,6 +15,7 @@ */ package com.intellij.usages.impl.rules; +import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vcs.FileStatus; import com.intellij.openapi.vfs.VirtualFile; @@ -46,29 +47,51 @@ public class UsageScopeGroupingRule implements UsageGroupingRule { if (virtualFile == null) { return null; } - boolean isInTest = ProjectRootManager.getInstance(element.getProject()).getFileIndex().isInTestSourceContent(virtualFile); + ProjectFileIndex fileIndex = ProjectRootManager.getInstance(element.getProject()).getFileIndex(); + boolean isInLib = fileIndex.isInLibraryClasses(virtualFile) || fileIndex.isInLibrarySource(virtualFile); + if (isInLib) return LIBRARY; + boolean isInTest = fileIndex.isInTestSourceContent(virtualFile); return isInTest ? TEST : PRODUCTION; } - private static final UsageScopeGroup TEST = new UsageScopeGroup(true); - private static final UsageScopeGroup PRODUCTION = new UsageScopeGroup(false); - private static class UsageScopeGroup implements UsageGroup { - private final boolean isTest; - - private UsageScopeGroup(boolean isTest) { - this.isTest = isTest; - } - - public void update() { - } - + private static final UsageScopeGroup TEST = new UsageScopeGroup(0) { public Icon getIcon(boolean isOpen) { - return isTest ? Icons.TEST_SOURCE_FOLDER : Icons.SOURCE_FOLDERS_ICON; + return Icons.TEST_SOURCE_FOLDER; } @NotNull public String getText(UsageView view) { - return isTest ? "Test" : "Production"; + return "Test"; + } + }; + private static final UsageScopeGroup PRODUCTION = new UsageScopeGroup(1) { + public Icon getIcon(boolean isOpen) { + return Icons.SOURCE_FOLDERS_ICON ; + } + + @NotNull + public String getText(UsageView view) { + return "Production"; + } + }; + private static final UsageScopeGroup LIBRARY = new UsageScopeGroup(2) { + public Icon getIcon(boolean isOpen) { + return Icons.LIBRARY_ICON ; + } + + @NotNull + public String getText(UsageView view) { + return "Library"; + } + }; + private abstract static class UsageScopeGroup implements UsageGroup { + private final int myCode; + + private UsageScopeGroup(int code) { + myCode = code; + } + + public void update() { } public FileStatus getFileStatus() { @@ -91,11 +114,11 @@ public class UsageScopeGroupingRule implements UsageGroupingRule { if (this == o) return true; if (!(o instanceof UsageScopeGroup)) return false; final UsageScopeGroup usageTypeGroup = (UsageScopeGroup)o; - return isTest == usageTypeGroup.isTest; + return myCode == usageTypeGroup.myCode; } public int hashCode() { - return isTest ? 0 : 1; + return myCode; } } } diff --git a/platform/util/src/com/intellij/execution/rmi/RemoteCastable.java b/platform/util/src/com/intellij/execution/rmi/RemoteCastable.java new file mode 100644 index 000000000000..28395a18b04d --- /dev/null +++ b/platform/util/src/com/intellij/execution/rmi/RemoteCastable.java @@ -0,0 +1,11 @@ +package com.intellij.execution.rmi; + +import java.rmi.Remote; +import java.rmi.RemoteException; + +/** + * @author Gregory.Shrago + */ +public interface RemoteCastable extends Remote { + String getCastToClassName() throws RemoteException; +} diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index 35b239a3bde3..26441f3f75e7 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -968,6 +968,10 @@ public class FileUtil { } } + public static void appendToFile(File file, String text) throws IOException { + writeToFile(file, text.getBytes("UTF-8"), true); + } + public static void writeToFile(final File file, final byte[] text) throws IOException { writeToFile(file, text, false); } @@ -981,9 +985,10 @@ public class FileUtil { finally { stream.close(); } - } + + public static boolean processFilesRecursively(final File root, final Processor processor) { final LinkedList queue = new LinkedList(); queue.add(root); diff --git a/platform/util/src/com/intellij/ui/TableUtil.java b/platform/util/src/com/intellij/ui/TableUtil.java index 4105ecd1bb47..b9f625cc061d 100644 --- a/platform/util/src/com/intellij/ui/TableUtil.java +++ b/platform/util/src/com/intellij/ui/TableUtil.java @@ -49,15 +49,17 @@ public class TableUtil { ListSelectionModel selectionModel = table.getSelectionModel(); int maxSelectionIndex = selectionModel.getMaxSelectionIndex(); int minSelectionIndex = selectionModel.getMinSelectionIndex(); - if(maxSelectionIndex == -1){ + final int maxColumnSelectionIndex = table.getColumnModel().getSelectionModel().getMinSelectionIndex(); + final int minColumnSelectionIndex = table.getColumnModel().getSelectionModel().getMaxSelectionIndex(); + if(maxSelectionIndex == -1 || maxColumnSelectionIndex == -1){ return; } - Rectangle minCellRect = table.getCellRect(minSelectionIndex, 0, false); - Rectangle maxCellRect = table.getCellRect(maxSelectionIndex, 0, false); + Rectangle minCellRect = table.getCellRect(minSelectionIndex, minColumnSelectionIndex, false); + Rectangle maxCellRect = table.getCellRect(maxSelectionIndex, maxColumnSelectionIndex, false); Point selectPoint = minCellRect.getLocation(); int allHeight = maxCellRect.y + maxCellRect.height - minCellRect.y; allHeight = Math.min(allHeight, table.getVisibleRect().height); - table.scrollRectToVisible(new Rectangle(selectPoint, new Dimension(1,allHeight))); + table.scrollRectToVisible(new Rectangle(selectPoint, new Dimension(minCellRect.width / 2,allHeight))); } public static List removeSelectedItems(JTable table, ItemChecker applyable) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchForBaseRevisionTexts.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchForBaseRevisionTexts.java index 6045891e067b..ca3347d49231 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchForBaseRevisionTexts.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchForBaseRevisionTexts.java @@ -37,7 +37,7 @@ public class ApplyPatchForBaseRevisionTexts { @Nullable public static ApplyPatchForBaseRevisionTexts create(final Project project, final VirtualFile file, final FilePath pathBeforeRename, final TextFilePatch patch) { - + if (patch.isNewFile()) return createForAddition(patch); final String beforeVersionId = patch.getBeforeVersionId(); if (beforeVersionId == null) { return null; @@ -49,6 +49,29 @@ public class ApplyPatchForBaseRevisionTexts { return null; } + @Nullable + private static ApplyPatchForBaseRevisionTexts createForAddition(final TextFilePatch patch) { + final StringBuilder newText = new StringBuilder(); + try { + final ApplyPatchStatus status = ApplyFilePatchBase.applyModifications(patch, "", newText); + return new ApplyPatchForBaseRevisionTexts("", null, "", newText.toString(), status); + } + catch (ApplyPatchException e) { + return new ApplyPatchForBaseRevisionTexts(null, new VcsException(e), null, null, ApplyPatchStatus.FAILURE); + } + } + + private ApplyPatchForBaseRevisionTexts(CharSequence base, VcsException exception, + CharSequence local, + String patched, + ApplyPatchStatus status) { + myBase = base; + myException = exception; + myLocal = local; + myPatched = patched; + myStatus = status; + } + ApplyPatchForBaseRevisionTexts(final DefaultPatchBaseVersionProvider provider, final FilePath pathBeforeRename, final TextFilePatch patch, final VirtualFile file) { myLocal = LoadTextUtil.loadText(file); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/DiffShelvedChangesAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/DiffShelvedChangesAction.java index a5ec39969922..33fb014f80fc 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/DiffShelvedChangesAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/DiffShelvedChangesAction.java @@ -80,7 +80,7 @@ public class DiffShelvedChangesAction extends AnAction implements DumbAware { final String beforePath = shelvedChange.getBeforePath(); try { final VirtualFile f = ApplyTextFilePatch.findPatchTarget(context, beforePath, shelvedChange.getAfterPath(), FileStatus.ADDED.equals(shelvedChange.getFileStatus())); - if ((f == null) || (! f.exists())) { + if ((! FileStatus.ADDED.equals(shelvedChange.getFileStatus())) && ((f == null) || (! f.exists()))) { if (beforePath != null) { missing.add(beforePath); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java index c75077a03485..11afa03947b8 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java @@ -396,9 +396,7 @@ public class LineStatusTrackerManager implements ProjectComponent { } } - private void trackAwtThread() { - if (! ApplicationManager.getApplication().isDispatchThread()) { - LOG.warn("NOT dispatch thread: " + Thread.currentThread().getName(), new Throwable()); - } + private static void trackAwtThread() { + ApplicationManager.getApplication().assertIsDispatchThread(); } } diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XFullValueEvaluator.java b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XFullValueEvaluator.java index 3ec8db62b142..881663e510d2 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XFullValueEvaluator.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XFullValueEvaluator.java @@ -17,6 +17,9 @@ package com.intellij.xdebugger.frame; import com.intellij.xdebugger.Obsolescent; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; /** * Supports asynchronous fetching full text of a value. If full text is already computed use {@link ImmediateFullValueEvaluator} @@ -48,6 +51,8 @@ public abstract class XFullValueEvaluator { public interface XFullValueEvaluationCallback extends Obsolescent { void evaluated(@NotNull String fullValue); + void evaluated(@NotNull String fullValue, @Nullable Font font); + void errorOccurred(@NotNull String errorMessage); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java index 22a7c69f44c7..202fef7348a9 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java @@ -22,17 +22,22 @@ import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.DimensionService; import com.intellij.openapi.wm.WindowManager; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.awt.RelativePoint; import com.intellij.xdebugger.frame.XFullValueEvaluator; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; +import java.util.concurrent.atomic.AtomicBoolean; /** * User: lex @@ -40,6 +45,8 @@ import java.awt.event.MouseEvent; * Time: 11:26:44 PM */ public class DebuggerUIUtil { + @NonNls public static final String FULL_VALUE_POPUP_DIMENSION_KEY = "XDebugger.FullValuePopup"; + private DebuggerUIUtil() { } @@ -93,43 +100,58 @@ public class DebuggerUIUtil { public static void showValuePopup(@NotNull XFullValueEvaluator text, @NotNull MouseEvent event, @NotNull Project project) { final JTextArea textArea = new JTextArea("Evaluating..."); + final FullValueEvaluationCallbackImpl callback = new FullValueEvaluationCallbackImpl(textArea); + text.startEvaluation(callback); textArea.setEditable(false); textArea.setBackground(HintUtil.INFORMATION_COLOR); textArea.setLineWrap(false); final JScrollPane component = ScrollPaneFactory.createScrollPane(textArea); final Dimension frameSize = WindowManager.getInstance().getFrame(project).getSize(); - final Dimension size = new Dimension(frameSize.width / 2, frameSize.height / 2); + Dimension size = DimensionService.getInstance().getSize(FULL_VALUE_POPUP_DIMENSION_KEY, project); + if (size == null) { + size = new Dimension(frameSize.width / 2, frameSize.height / 2); + } + component.setPreferredSize(size); component.setBorder(null); final JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(component, null) .setResizable(true) .setMovable(true) - .setDimensionServiceKey(project, "XDebugger.FullValuePopup", false) + .setDimensionServiceKey(project, FULL_VALUE_POPUP_DIMENSION_KEY, false) .setRequestFocus(false) + .setCancelCallback(new Computable() { + public Boolean compute() { + callback.setObsolete(); + return true; + } + }) .createPopup(); - - text.startEvaluation(new FullValueEvaluationCallbackImpl(popup, textArea)); - final Component parentComponent = event.getComponent(); RelativePoint point = new RelativePoint(parentComponent, new Point(event.getX()-size.width, event.getY()-size.height)); popup.show(point); } private static class FullValueEvaluationCallbackImpl implements XFullValueEvaluator.XFullValueEvaluationCallback { - private final JBPopup myPopup; + private final AtomicBoolean myObsolete = new AtomicBoolean(false); private final JTextArea myTextArea; - public FullValueEvaluationCallbackImpl(final JBPopup popup, final JTextArea textArea) { - myPopup = popup; + public FullValueEvaluationCallbackImpl(final JTextArea textArea) { myTextArea = textArea; } public void evaluated(@NotNull final String fullValue) { + evaluated(fullValue, null); + } + + public void evaluated(@NotNull final String fullValue, @Nullable final Font font) { invokeOnEventDispatch(new Runnable() { public void run() { myTextArea.setText(fullValue); + if (font != null) { + myTextArea.setFont(font); + } myTextArea.setCaretPosition(0); } }); @@ -144,8 +166,12 @@ public class DebuggerUIUtil { }); } + private void setObsolete() { + myObsolete.set(true); + } + public boolean isObsolete() { - return myPopup.isDisposed(); + return myObsolete.get(); } } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTree.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTree.java index 6955e5f55ef3..d002d1f2da1a 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTree.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTree.java @@ -47,13 +47,15 @@ public class XDebuggerTree extends DnDAwareTree implements DataProvider { private static final DataKey XDEBUGGER_TREE_KEY = DataKey.create("xdebugger.tree"); private static final Convertor SPEED_SEARCH_CONVERTER = new Convertor() { public String convert(TreePath o) { - final Object node = o.getLastPathComponent(); String text = null; - if (node instanceof XValueNodeImpl) { - text = ((XValueNodeImpl)node).getName(); - } - else if (node instanceof XDebuggerTreeNode) { - text = ((XDebuggerTreeNode)node).getText().toString(); + if (o != null) { + final Object node = o.getLastPathComponent(); + if (node instanceof XValueNodeImpl) { + text = ((XValueNodeImpl)node).getName(); + } + else if (node instanceof XDebuggerTreeNode) { + text = ((XDebuggerTreeNode)node).getText().toString(); + } } return text != null ? text : ""; } diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 5022b47253df..f9cd0be71344 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -2,7 +2,7 @@ plugin.InspectionGadgets.description=Adds over 500 new automated code inspection error.message.regexp.malformed.naming.pattern=Malformed Naming Pattern error.message.regexp.malformed.pattern=Malformed Regular Expression Pattern cast.to.concrete.class.display.name=Cast to a concrete class -cast.to.concrete.class.problem.descriptor=Cast to concrete class #ref #loc +cast.to.concrete.class.problem.descriptor=Cast to concrete class {0} #loc class.references.subclass.display.name=Class references one of its subclasses class.references.subclass.problem.descriptor=Class ''{0}'' references subclass #ref #loc class.references.subclass.problem.descriptor.anonymous=Anonymous class references subclass #ref #loc @@ -1767,3 +1767,7 @@ ignore.single.field.static.imports.option=Ignore single &field static imports ignore.single.method.static.imports.option=Ignore single &method static imports ignore.methods.with.boolean.return.type.option=Ignore methods with &Boolean return type ignore.boolean.methods.in.an.interface.option=Ignore boolean methods in an @&interface +ignored.io.resource.types=Ignored I/O resource types +choose.io.resource.type.to.ignore=Choose I/O resource type to ignore +ignore.accesses.from.the.same.class=ignore accesses from the same class +ignore.accesses.from.equals.method=ignore accesses from 'equals()' method diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/CastToConcreteClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/CastToConcreteClassInspection.java index 16925f51250f..c827384a5a68 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/CastToConcreteClassInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/CastToConcreteClassInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,27 +15,32 @@ */ package com.siyeh.ig.abstraction; -import com.intellij.psi.PsiTypeCastExpression; -import com.intellij.psi.PsiTypeElement; +import com.intellij.psi.*; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; public class CastToConcreteClassInspection extends BaseInspection { + @Override @NotNull public String getDisplayName() { return InspectionGadgetsBundle.message( "cast.to.concrete.class.display.name"); } + @Override @NotNull protected String buildErrorString(Object... infos) { + final PsiElement typeElement = (PsiElement) infos[0]; return InspectionGadgetsBundle.message( - "cast.to.concrete.class.problem.descriptor"); + "cast.to.concrete.class.problem.descriptor", + typeElement.getText()); } + @Override public BaseInspectionVisitor buildVisitor() { return new CastToConcreteClassVisitor(); } @@ -47,13 +52,39 @@ public class CastToConcreteClassInspection extends BaseInspection { @NotNull PsiTypeCastExpression expression) { super.visitTypeCastExpression(expression); final PsiTypeElement typeElement = expression.getCastType(); - if (!ConcreteClassUtil.typeIsConcreteClass(typeElement)) { - return; - } if (typeElement == null) { return; } - registerError(typeElement); + if (!ConcreteClassUtil.typeIsConcreteClass(typeElement)) { + return; + } + registerError(typeElement, typeElement); + } + + @Override + public void visitMethodCallExpression( + PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = + expression.getMethodExpression(); + @NonNls + final String referenceName = methodExpression.getReferenceName(); + if (!"cast".equals(referenceName)) { + return; + } + final PsiExpression qualifier = + methodExpression.getQualifierExpression(); + if (!(qualifier instanceof PsiClassObjectAccessExpression)) { + return; + } + final PsiClassObjectAccessExpression classObjectAccessExpression = + (PsiClassObjectAccessExpression) qualifier; + final PsiTypeElement operand = + classObjectAccessExpression.getOperand(); + if (!ConcreteClassUtil.typeIsConcreteClass(operand)) { + return; + } + registerMethodCallError(expression, operand); } } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/UseOfAnotherObjectsPrivateFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/UseOfAnotherObjectsPrivateFieldInspection.java index 6b5d6892507d..8e7af21cfa6c 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/UseOfAnotherObjectsPrivateFieldInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/UseOfAnotherObjectsPrivateFieldInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,37 +16,63 @@ package com.siyeh.ig.encapsulation; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.MethodUtils; +import com.siyeh.ig.ui.MultipleCheckboxOptionsPanel; import org.jetbrains.annotations.NotNull; +import javax.swing.*; + public class UseOfAnotherObjectsPrivateFieldInspection extends BaseInspection { + @SuppressWarnings({"PublicField"}) + public boolean ignoreSameClass = false; + @SuppressWarnings({"PublicField"}) + public boolean ignoreEquals = false; + + @Override @NotNull public String getID(){ return "AccessingNonPublicFieldOfAnotherObject"; } + @Override @NotNull public String getDisplayName(){ return InspectionGadgetsBundle.message( "accessing.non.public.field.of.another.object.display.name"); } + @Override @NotNull public String buildErrorString(Object... infos){ return InspectionGadgetsBundle.message( "accessing.non.public.field.of.another.object.problem.descriptor"); } + @Override + public JComponent createOptionsPanel() { + final MultipleCheckboxOptionsPanel panel = + new MultipleCheckboxOptionsPanel(this); + panel.addCheckbox(InspectionGadgetsBundle.message( + "ignore.accesses.from.the.same.class"), "ignoreSameClass"); + panel.addCheckbox(InspectionGadgetsBundle.message( + "ignore.accesses.from.equals.method"), "ignoreEquals"); + return panel; + } + + @Override public BaseInspectionVisitor buildVisitor(){ return new UseOfAnotherObjectsPrivateFieldVisitor(); } - private static class UseOfAnotherObjectsPrivateFieldVisitor + private class UseOfAnotherObjectsPrivateFieldVisitor extends BaseInspectionVisitor{ + @Override public void visitReferenceExpression( @NotNull PsiReferenceExpression expression){ super.visitReferenceExpression(expression); @@ -54,11 +80,26 @@ public class UseOfAnotherObjectsPrivateFieldInspection if(qualifier == null || qualifier instanceof PsiThisExpression){ return; } + if(ignoreEquals) { + final PsiMethod method = + PsiTreeUtil.getParentOfType(expression, PsiMethod.class); + if (MethodUtils.isEquals(method)) { + return; + } + } final PsiElement referent = expression.resolve(); if(!(referent instanceof PsiField)){ return; } final PsiField field = (PsiField) referent; + if (ignoreSameClass) { + final PsiClass parent = + PsiTreeUtil.getParentOfType(expression, PsiClass.class); + final PsiClass containingClass = field.getContainingClass(); + if (parent != null && parent.equals(containingClass)) { + return; + } + } if(!field.hasModifierProperty(PsiModifier.PRIVATE) && !field.hasModifierProperty(PsiModifier.PROTECTED)){ return; @@ -68,7 +109,7 @@ public class UseOfAnotherObjectsPrivateFieldInspection } final PsiElement fieldNameElement = expression.getReferenceNameElement(); - if (fieldNameElement == null) { + if(fieldNameElement == null){ return; } registerError(fieldNameElement); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MapReplaceableByEnumMapInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MapReplaceableByEnumMapInspection.java index e5fc54c4183c..99a1fbf2f1ee 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MapReplaceableByEnumMapInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MapReplaceableByEnumMapInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,18 +27,21 @@ import org.jetbrains.annotations.NotNull; public class MapReplaceableByEnumMapInspection extends BaseInspection { + @Override @NotNull public String getDisplayName() { return InspectionGadgetsBundle.message( "map.replaceable.by.enum.map.display.name"); } + @Override @NotNull protected String buildErrorString(Object... infos) { return InspectionGadgetsBundle.message( "map.replaceable.by.enum.map.problem.descriptor"); } + @Override public BaseInspectionVisitor buildVisitor() { return new SetReplaceableByEnumSetVisitor(); } @@ -46,7 +49,8 @@ public class MapReplaceableByEnumMapInspection extends BaseInspection { private static class SetReplaceableByEnumSetVisitor extends BaseInspectionVisitor { - @Override public void visitNewExpression(@NotNull PsiNewExpression expression) { + @Override public void visitNewExpression( + @NotNull PsiNewExpression expression) { super.visitNewExpression(expression); final PsiType type = expression.getType(); if (!(type instanceof PsiClassType)) { @@ -65,19 +69,16 @@ public class MapReplaceableByEnumMapInspection extends BaseInspection { return; } if (!TypeUtils.expressionHasTypeOrSubtype(expression, - "java.util.Map")) { + "java.util.Map")) { return; } - if (TypeUtils.expressionHasTypeOrSubtype(expression, - "java.util.EnumMap")) { - return; + if (null != TypeUtils.expressionHasTypeOrSubtype(expression, + "java.util.EnumMap", "java.util.concurrent.ConcurrentMap")) { + return; } final PsiClassType argumentClassType = (PsiClassType)argumentType; final PsiClass argumentClass = argumentClassType.resolve(); - if (argumentClass == null) { - return; - } - if (!argumentClass.isEnum()) { + if (argumentClass == null || !argumentClass.isEnum()) { return; } registerNewExpressionError(expression); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/SetReplaceableByEnumSetInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/SetReplaceableByEnumSetInspection.java index cbf4cd68668c..1ad5ad6152d5 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/SetReplaceableByEnumSetInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/SetReplaceableByEnumSetInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,18 +27,21 @@ import org.jetbrains.annotations.NotNull; public class SetReplaceableByEnumSetInspection extends BaseInspection { + @Override @NotNull public String getDisplayName() { return InspectionGadgetsBundle.message( "set.replaceable.by.enum.set.display.name"); } + @Override @NotNull protected String buildErrorString(Object... infos) { return InspectionGadgetsBundle.message( "set.replaceable.by.enum.set.problem.descriptor"); } + @Override public BaseInspectionVisitor buildVisitor() { return new SetReplaceableByEnumSetVisitor(); } @@ -46,7 +49,8 @@ public class SetReplaceableByEnumSetInspection extends BaseInspection { private static class SetReplaceableByEnumSetVisitor extends BaseInspectionVisitor { - @Override public void visitNewExpression(@NotNull PsiNewExpression expression) { + @Override public void visitNewExpression( + @NotNull PsiNewExpression expression) { super.visitNewExpression(expression); final PsiType type = expression.getType(); if (!(type instanceof PsiClassType)) { @@ -65,11 +69,11 @@ public class SetReplaceableByEnumSetInspection extends BaseInspection { return; } if (!TypeUtils.expressionHasTypeOrSubtype(expression, - "java.util.Set")) { + "java.util.Set")) { return; } if (TypeUtils.expressionHasTypeOrSubtype(expression, - "java.util.EnumSet")) { + "java.util.EnumSet")) { return; } final PsiClassType argumentClassType = (PsiClassType)argumentType; diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/resources/IOResourceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/resources/IOResourceInspection.java index 40a0eacff5b9..6abbea700f3d 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/resources/IOResourceInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/resources/IOResourceInspection.java @@ -93,7 +93,8 @@ public class IOResourceInspection extends ResourceInspection { constraints.fill = GridBagConstraints.BOTH; final IGTable table = new IGTable(new ListWrappingTableModel(ignoredTypes, - "ignored io resource types")); + InspectionGadgetsBundle.message( + "ignored.io.resource.types"))); final JScrollPane scrollPane = new JScrollPane(table); panel.add(scrollPane, constraints); constraints.gridx = 1; @@ -103,7 +104,11 @@ public class IOResourceInspection extends ResourceInspection { constraints.fill = GridBagConstraints.HORIZONTAL; final JButton addButton = new JButton(new TreeClassChooserAction(table, - "Choose io resource type to ignore")); + InspectionGadgetsBundle.message( + "choose.io.resource.type.to.ignore"), + "java.io.InputStream", "java.io.OutputStream", + "java.io.Reader", "java.io.Writer", + "java.io.RandomAccessFile")); panel.add(addButton, constraints); constraints.gridy = 1; final JButton removeButton = new JButton(new RemoveAction(table)); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/resources/ResourceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/resources/ResourceInspection.java index 51869d384383..cfd7641fd1d5 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/resources/ResourceInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/resources/ResourceInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 Bas Leijdekkers + * Copyright 2008-2010 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,31 +58,44 @@ public abstract class ResourceInspection extends BaseInspection { return parent; } - protected static boolean isSafelyClosed(@Nullable PsiVariable boundVariable, - PsiExpression creationContext - ) { - if (boundVariable == null) { + protected static boolean isSafelyClosed(@Nullable PsiVariable variable, + PsiElement context) { + if (variable == null) { return false; } - final PsiStatement statement = - PsiTreeUtil.getParentOfType(creationContext, PsiStatement.class); + PsiStatement statement = + PsiTreeUtil.getParentOfType(context, PsiStatement.class); if (statement == null) { return false; } - final PsiStatement nextStatement = + PsiStatement nextStatement = PsiTreeUtil.getNextSiblingOfType(statement, PsiStatement.class); + while (nextStatement == null) { + statement = PsiTreeUtil.getParentOfType(statement, + PsiStatement.class, true); + if (statement == null) { + return false; + } + final PsiElement parent = statement.getParent(); + if (parent instanceof PsiIfStatement) { + statement = (PsiStatement) parent; + } + nextStatement = + PsiTreeUtil.getNextSiblingOfType(statement, + PsiStatement.class); + } if (!(nextStatement instanceof PsiTryStatement)) { // exception in next statement can prevent closing of the resource - return false; + return isResourceClose(nextStatement, variable); } final PsiTryStatement tryStatement = (PsiTryStatement) nextStatement; - return resourceIsClosedInFinally(tryStatement, boundVariable); + return resourceIsClosedInFinally(tryStatement, variable); } protected static boolean resourceIsClosedInFinally( @NotNull PsiTryStatement tryStatement, - @NotNull PsiVariable boundVariable) { + @NotNull PsiVariable variable) { final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); if (finallyBlock == null) { return false; @@ -91,11 +104,27 @@ public abstract class ResourceInspection extends BaseInspection { if (tryBlock == null) { return false; } - final CloseVisitor visitor = new CloseVisitor(boundVariable); + final CloseVisitor visitor = new CloseVisitor(variable); finallyBlock.accept(visitor); return visitor.containsClose(); } + private static boolean isResourceClose(PsiStatement nextStatement, + PsiVariable variable) { + if (!(nextStatement instanceof PsiExpressionStatement)) { + return false; + } + final PsiExpressionStatement expressionStatement = + (PsiExpressionStatement) nextStatement; + final PsiExpression expression = expressionStatement.getExpression(); + if (!(expression instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression methodCallExpression = + (PsiMethodCallExpression) expression; + return isResourceClose(methodCallExpression, variable); + } + protected static boolean isResourceEscapedFromMethod( PsiVariable boundVariable, PsiElement context){ // poor man dataflow @@ -114,6 +143,24 @@ public abstract class ResourceInspection extends BaseInspection { return visitor.isEscaped(); } + protected static boolean isResourceClose(PsiMethodCallExpression call, + PsiVariable resource) { + final PsiReferenceExpression methodExpression = + call.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if (!HardcodedMethodConstants.CLOSE.equals(methodName)) { + return false; + } + final PsiExpression qualifier = + methodExpression.getQualifierExpression(); + if (!(qualifier instanceof PsiReferenceExpression)) { + return false; + } + final PsiReference reference = (PsiReference) qualifier; + final PsiElement referent = reference.resolve(); + return referent != null && referent.equals(resource); + } + private static class CloseVisitor extends JavaRecursiveElementVisitor { private boolean containsClose = false; @@ -148,7 +195,7 @@ public abstract class ResourceInspection extends BaseInspection { @Override public void visitReferenceExpression( PsiReferenceExpression referenceExpression) { - // check if resource is closed in IOUtils.silentClose() like method + // check if resource is closed in a method like IOUtils.silentClose() super.visitReferenceExpression(referenceExpression); if (containsClose) { return; @@ -222,24 +269,6 @@ public abstract class ResourceInspection extends BaseInspection { } } - private static boolean isResourceClose(PsiMethodCallExpression call, - PsiVariable resource) { - final PsiReferenceExpression methodExpression = - call.getMethodExpression(); - final String methodName = methodExpression.getReferenceName(); - if (!HardcodedMethodConstants.CLOSE.equals(methodName)) { - return false; - } - final PsiExpression qualifier = - methodExpression.getQualifierExpression(); - if (!(qualifier instanceof PsiReferenceExpression)) { - return false; - } - final PsiReference reference = (PsiReference) qualifier; - final PsiElement referent = reference.resolve(); - return referent != null && referent.equals(resource); - } - public boolean containsClose() { return containsClose; } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/ui/TreeClassChooserAction.java b/plugins/InspectionGadgets/src/com/siyeh/ig/ui/TreeClassChooserAction.java index f598eb402927..01262a1ba341 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/ui/TreeClassChooserAction.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/ui/TreeClassChooserAction.java @@ -22,33 +22,61 @@ import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.DataKeys; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiClass; +import com.intellij.psi.search.GlobalSearchScope; import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.psiutils.ClassUtils; +import org.jetbrains.annotations.NonNls; -import javax.swing.AbstractAction; -import javax.swing.ListSelectionModel; -import java.awt.EventQueue; -import java.awt.Rectangle; +import javax.swing.*; +import java.awt.*; import java.awt.event.ActionEvent; public class TreeClassChooserAction extends AbstractAction { private final IGTable table; private final String chooserTitle; + private final String[] ancestorClasses; - public TreeClassChooserAction(IGTable table, String chooserTitle) { + public TreeClassChooserAction(IGTable table, String chooserTitle, + @NonNls String... ancestorClasses) { this.table = table; this.chooserTitle = chooserTitle; + this.ancestorClasses = ancestorClasses; putValue(NAME, InspectionGadgetsBundle.message("button.add")); } public void actionPerformed(ActionEvent e) { final DataManager dataManager = DataManager.getInstance(); - final DataContext dataContext = dataManager.getDataContext(); + final Object source = e.getSource(); + if (!(source instanceof Component)) { + return; + } + final DataContext dataContext = + dataManager.getDataContext((Component) source); final Project project = DataKeys.PROJECT.getData(dataContext); + if (project == null) { + return; + } final TreeClassChooserFactory chooserFactory = TreeClassChooserFactory.getInstance(project); + final TreeClassChooser.ClassFilter filter; + if (ancestorClasses.length == 0) { + filter = TreeClassChooser.ClassFilter.ALL; + } else { + filter = new TreeClassChooser.ClassFilter() { + public boolean isAccepted(PsiClass aClass) { + for (String ancestorClass : ancestorClasses) { + if (ClassUtils.isSubclass(aClass, ancestorClass)) { + return true; + } + } + return false; + } + }; + } final TreeClassChooser classChooser = - chooserFactory.createAllProjectScopeChooser(chooserTitle); + chooserFactory.createWithInnerClassesScopeChooser(chooserTitle, + GlobalSearchScope.allScope(project), filter, null); classChooser.showDialog(); final PsiClass selectedClass = classChooser.getSelectedClass(); if (selectedClass == null) { diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleCheckedLocking.html b/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleCheckedLocking.html index bc221bf6a858..24e5b8c23c52 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleCheckedLocking.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleCheckedLocking.html @@ -7,8 +7,7 @@ discussion of double-checked locking and why it is unsafe, see ">http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

    Use the checkbox below to ignore double-checked locking on volatile fields. Using -a volatile field for double-checked locking works correctly on Java 5 virtual machines, -but probably does not have any performance advantages over plain full synchronization -of the accessor method. +a volatile field for double-checked locking works correctly on virtual machines which +implement the new Java Memory Model. Powered by InspectionGadgets \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UseOfAnotherObjectsPrivateField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UseOfAnotherObjectsPrivateField.html index 8e451ab6f44d..6b77662bb194 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/UseOfAnotherObjectsPrivateField.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UseOfAnotherObjectsPrivateField.html @@ -7,5 +7,10 @@ some coding styles discourage this use. Additionally, such direct access to pri may fail in component-oriented architectures such (e.g. Spring, Hibernate) which expect all access to other objects to be through method calls so as to allow the framework to mediate all access using proxies. +

    +Use the first checkbox below to ignore accesses from the same class and only report accesses +from inner or outer classes.
    +Use the second checkbox below to ignore accesses from an equals() method. +

    Powered by InspectionGadgets \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/resources/io/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/resources/io/expected.xml index 73fb8e116284..02011abf6f4a 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/resources/io/expected.xml +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/resources/io/expected.xml @@ -50,39 +50,6 @@ 'FileInputStream' should be opened in front of a try block and closed in the corresponding finally block #loc - - - IOResourceInspection.java - 32 - - void foo3() - foo3() - com.siyeh.igtest.resources - - IOResourceInspection - IOResourceInspection - - - I/O resource opened but not safely closed - 'FileInputStream' should be opened in front of a try block and closed in the corresponding finally block #loc - - - - IOResourceInspection.java - 39 - - void foo4() - foo4() - com.siyeh.igtest.resources - - IOResourceInspection - IOResourceInspection - - - I/O resource opened but not safely closed - 'FileInputStream' should be opened in front of a try block and closed in the corresponding finally block #loc - - IOResourceInspection.java 57 diff --git a/plugins/consoleFolding/src/META-INF/plugin.xml b/plugins/consoleFolding/src/META-INF/plugin.xml index 77404cf53955..581ba8ab2662 100644 --- a/plugins/consoleFolding/src/META-INF/plugin.xml +++ b/plugins/consoleFolding/src/META-INF/plugin.xml @@ -3,7 +3,7 @@ Console Folding Adds a customization for folding non-interesting lines in console 0.1 - + JetBrains Inc. diff --git a/plugins/consoleFolding/src/com/intellij/execution/ConsoleFoldingSettings.java b/plugins/consoleFolding/src/com/intellij/execution/ConsoleFoldingSettings.java index 50e0b6c010f0..43c1f8668f73 100644 --- a/plugins/consoleFolding/src/com/intellij/execution/ConsoleFoldingSettings.java +++ b/plugins/consoleFolding/src/com/intellij/execution/ConsoleFoldingSettings.java @@ -25,14 +25,12 @@ public class ConsoleFoldingSettings implements PersistentStateComponent patterns) { + for (String pattern : patterns) { if (line.contains(pattern)) { - for (String negativePattern : myNegativePatterns) { - if (line.contains(negativePattern)) { - continue positive; - } - } return true; } } diff --git a/plugins/groovy/grape/src/META-INF/plugin.xml b/plugins/groovy/grape/src/META-INF/plugin.xml index 69d1b78d6c98..642560f65642 100644 --- a/plugins/groovy/grape/src/META-INF/plugin.xml +++ b/plugins/groovy/grape/src/META-INF/plugin.xml @@ -3,7 +3,7 @@ Groovy Grape support An intention on @Grab annotations to download the needed dependencies 0.4 - + JetBrains Inc. org.intellij.groovy diff --git a/plugins/groovy/groovypp/groovypp.iml b/plugins/groovy/groovypp/groovypp.iml new file mode 100644 index 000000000000..c80576200148 --- /dev/null +++ b/plugins/groovy/groovypp/groovypp.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/plugins/groovy/groovypp/src/META-INF/plugin.xml b/plugins/groovy/groovypp/src/META-INF/plugin.xml new file mode 100644 index 000000000000..a6362ad471ad --- /dev/null +++ b/plugins/groovy/groovypp/src/META-INF/plugin.xml @@ -0,0 +1,19 @@ + + org.intellij.groovy.gpp + Groovy++ Support + Adds code assistance for the Groovy++ features + 0.1 + + JetBrains Inc. + org.intellij.groovy + + + + + + + + + + + diff --git a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppClassSubstitutor.java b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppClassSubstitutor.java new file mode 100644 index 000000000000..0ff387114a89 --- /dev/null +++ b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppClassSubstitutor.java @@ -0,0 +1,35 @@ +package org.jetbrains.plugins.groovy.gpp; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiModifierList; +import com.intellij.psi.impl.light.LightClass; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitution; +import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor; + +/** + * @author peter + */ +public class GppClassSubstitutor extends GrClassSubstitutor { + + @Override + public GrClassSubstitution substituteClass(@NotNull PsiClass base) { + final PsiModifierList modifierList = base.getModifierList(); + if (modifierList != null && modifierList.findAnnotation("groovy.lang.Trait") != null) { + return new TraitClass(base); + } + return null; + } + + private static class TraitClass extends LightClass implements GrClassSubstitution { + public TraitClass(PsiClass base) { + super(base); + } + + @Override + public boolean isInterface() { + return true; + } + + } +} diff --git a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java new file mode 100644 index 000000000000..7a9548292da7 --- /dev/null +++ b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java @@ -0,0 +1,188 @@ +package org.jetbrains.plugins.groovy.gpp; + +import com.intellij.codeInsight.generation.OverrideImplementUtil; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.*; +import com.intellij.psi.infos.CandidateInfo; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.AbstractClosureParameterEnhancer; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; +import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil; + +import java.util.*; + +/** + * @author peter + */ +public class GppClosureParameterTypeProvider extends AbstractClosureParameterEnhancer { + @Override + protected PsiType getClosureParameterType(GrClosableBlock closure, int index) { + if (!GppTypeConverter.hasTypedContext(closure)) { + return null; + } + + final Pair pair = getOverriddenMethod(closure); + if (pair != null) { + final PsiParameter[] parameters = pair.first.getParameterList().getParameters(); + if (parameters.length > index) { + return pair.second.substitute(parameters[index].getType()); + } + return null; + } + + final PsiElement parent = closure.getParent(); + if (parent instanceof GrListOrMap) { + final GrListOrMap list = (GrListOrMap)parent; + if (!list.isMap()) { + final PsiType listType = list.getType(); + final int argIndex = Arrays.asList(list.getInitializers()).indexOf(closure); + assert argIndex >= 0; + if (listType instanceof GrTupleType) { + for (PsiType type : GroovyExpectedTypesProvider.getDefaultExpectedTypes(list)) { + if (type instanceof PsiClassType) { + for (GroovyResolveResult resolveResult : GppTypeConverter + .getConstructorCandidates((PsiClassType)type, ((GrTupleType)listType).getComponentTypes(), closure)) { + final PsiElement method = resolveResult.getElement(); + if (method instanceof PsiMethod && ((PsiMethod)method).isConstructor()) { + final PsiType toCastTo = + resolveResult.getSubstitutor().substitute(((PsiMethod)method).getParameterList().getParameters()[argIndex].getType()); + final PsiType suggestion = getSingleMethodParameterType(toCastTo, index, closure); + if (suggestion != null) { + return suggestion; + } + } + + } + } + } + } + return null; + } + } + + for (PsiType constraint : GroovyExpectedTypesProvider.getDefaultExpectedTypes(closure)) { + final PsiType suggestion = getSingleMethodParameterType(constraint, index, closure); + if (suggestion != null) { + return suggestion; + } + } + return null; + } + + @Nullable + private static Pair getOverriddenMethod(GrClosableBlock closure) { + final PsiElement parent = closure.getParent(); + if (!(parent instanceof GrNamedArgument)) { + return null; + } + + final GrArgumentLabel label = ((GrNamedArgument)parent).getLabel(); + if (label == null) { + return null; + } + + final String methodName = label.getName(); + if (methodName == null) { + return null; + } + + final PsiElement map = parent.getParent(); + if (map instanceof GrListOrMap && ((GrListOrMap)map).isMap()) { + for (PsiType expected : GroovyExpectedTypesProvider.getDefaultExpectedTypes((GrExpression)map)) { + if (expected instanceof PsiClassType) { + final List> pairs = getMethodsToOverrideImplementInInheritor((PsiClassType)expected, false); + final List> withName = + ContainerUtil.findAll(pairs, new Condition>() { + public boolean value(Pair pair) { + return methodName.equals(pair.first.getName()); + } + }); + if (withName.size() == 1) { + return withName.get(0); + } + } + } + } + + return null; + } + + @Nullable + private static PsiType getSingleMethodParameterType(@Nullable PsiType type, int index, GrClosableBlock closure) { + final PsiType[] signature = findSingleAbstractMethodSignature(type); + if (signature != null && GrClosureSignatureUtil.isSignatureApplicable(GrClosureSignatureUtil.createSignature(closure), signature, closure)) { + return signature.length > index ? signature[index] : PsiType.NULL; + } + return null; + } + + @Nullable + public static PsiType[] findSingleAbstractMethodSignature(@Nullable PsiType type) { + if (type instanceof PsiClassType) { + List> result = getMethodsToOverrideImplementInInheritor((PsiClassType)type, true); + if (result.size() == 1) { + final Pair pair = result.get(0); + return ContainerUtil.map2Array(pair.first.getParameterList().getParameters(), PsiType.class, new Function() { + public PsiType fun(PsiParameter psiParameter) { + return pair.second.substitute(psiParameter.getType()); + } + }); + } + } + return null; + } + + @NotNull + private static List> getMethodsToOverrideImplementInInheritor(PsiClassType classType, boolean toImplement) { + final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics(); + final PsiClass psiClass = resolveResult.getElement(); + if (psiClass == null) { + return Collections.emptyList(); + } + + List> over = getMethodsToOverrideImplement(psiClass, false); + List> impl = getMethodsToOverrideImplement(psiClass, true); + + for (PsiMethod method : psiClass.getMethods()) { + (method.hasModifierProperty(PsiModifier.ABSTRACT) ? impl : over).add(Pair.create(method, PsiSubstitutor.EMPTY)); + } + + for (Iterator> iterator = impl.iterator(); iterator.hasNext();) { + Pair pair = iterator.next(); + if (hasTraitImplementation(pair.first)) { + iterator.remove(); + over.add(pair); + } + } + + final List> result = toImplement ? impl : over; + for (int i = 0, resultSize = result.size(); i < resultSize; i++) { + Pair pair = result.get(i); + result.set(i, Pair.create(pair.first, resolveResult.getSubstitutor().putAll(pair.second))); + } + return result; + } + + private static ArrayList> getMethodsToOverrideImplement(PsiClass psiClass, final boolean toImplement) { + final ArrayList> result = new ArrayList>(); + for (CandidateInfo info : OverrideImplementUtil.getMethodsToOverrideImplement(psiClass, toImplement)) { + result.add(Pair.create((PsiMethod) info.getElement(), info.getSubstitutor())); + } + return result; + } + + private static boolean hasTraitImplementation(PsiMethod method) { + return method.getModifierList().findAnnotation("org.mbte.groovypp.runtime.HasDefaultImplementation") != null; + } +} diff --git a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppExpectedTypesContributor.java b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppExpectedTypesContributor.java new file mode 100644 index 000000000000..0c97a5c4beb6 --- /dev/null +++ b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppExpectedTypesContributor.java @@ -0,0 +1,69 @@ +package org.jetbrains.plugins.groovy.gpp; + +import com.intellij.psi.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesContributor; +import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider; +import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SubtypeConstraint; +import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * @author peter + */ +public class GppExpectedTypesContributor extends GroovyExpectedTypesContributor { + @Override + public List calculateTypeConstraints(@NotNull GrExpression expression) { + if (!GppTypeConverter.hasTypedContext(expression)) { + return Collections.emptyList(); + } + + final PsiElement parent = expression.getParent(); + if (parent instanceof GrListOrMap) { + final GrListOrMap list = (GrListOrMap)parent; + if (!list.isMap()) { + return addExpectedConstructorParameters(expression, list); + } + else { + //todo expected property types + } + } + return Collections.emptyList(); + } + + private static List addExpectedConstructorParameters(GrExpression expression, GrListOrMap list) { + final PsiType listType = list.getType(); + if (!(listType instanceof GrTupleType)) { + return Collections.emptyList(); + } + + final PsiType[] argTypes = ((GrTupleType)listType).getComponentTypes(); + final int argIndex = Arrays.asList(list.getInitializers()).indexOf(expression); + assert argIndex >= 0; + + final ArrayList result = new ArrayList(); + for (PsiType type : GroovyExpectedTypesProvider.getDefaultExpectedTypes(expression)) { + if (type instanceof PsiClassType) { + for (GroovyResolveResult resolveResult : GppTypeConverter.getConstructorCandidates((PsiClassType)type, argTypes, expression)) { + final PsiElement method = resolveResult.getElement(); + if (method instanceof PsiMethod && ((PsiMethod)method).isConstructor()) { + final PsiParameter[] constructorParameters = ((PsiMethod)method).getParameterList().getParameters(); + if (constructorParameters.length > argIndex) { + final PsiType toCastTo = resolveResult.getSubstitutor().substitute(constructorParameters[argIndex].getType()); + result.add(SubtypeConstraint.create(toCastTo)); + } + } + } + } + } + return result; + } +} diff --git a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppLibraryManager.java b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppLibraryManager.java new file mode 100644 index 000000000000..03511423fe1b --- /dev/null +++ b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppLibraryManager.java @@ -0,0 +1,121 @@ +package org.jetbrains.plugins.groovy.gpp; + +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.GroovyIcons; +import org.jetbrains.plugins.groovy.config.AbstractGroovyLibraryManager; + +import javax.swing.*; +import java.io.File; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author peter + */ +public class GppLibraryManager extends AbstractGroovyLibraryManager { + private static final Pattern GROOVYPP_JAR = Pattern.compile("groovypp-([\\d\\.]+)\\.jar"); + private static final Pattern GROOVYPP_ALL_JAR = Pattern.compile("groovypp-all-([\\d\\.]+)\\.jar"); + + @Override + protected void fillLibrary(String path, Library.ModifiableModel model) { + File lib = new File(path + "/lib"); + if (lib.exists()) { + model.addJarDirectory(VfsUtil.getUrlForLibraryRoot(lib), false); + } + + File srcRoot = new File(path + "/src"); + addSources(model, srcRoot.exists() ? srcRoot : new File(path)); + } + + private static void addSources(Library.ModifiableModel model, File srcRoot) { + File compilerSrc = new File(srcRoot, "Compiler/src"); + if (compilerSrc.exists()) { + model.addRoot(VfsUtil.getUrlForLibraryRoot(compilerSrc), OrderRootType.SOURCES); + } + + File stdLibSrc = new File(srcRoot, "StdLib/src"); + if (stdLibSrc.exists()) { + model.addRoot(VfsUtil.getUrlForLibraryRoot(stdLibSrc), OrderRootType.SOURCES); + } + + File mainSrc = new File(srcRoot, "main"); + if (mainSrc.exists()) { + model.addRoot(VfsUtil.getUrlForLibraryRoot(mainSrc), OrderRootType.SOURCES); + } + } + + @Override + public boolean managesLibrary(@NotNull Library library, LibrariesContainer container) { + return getGppVersion(container.getLibraryFiles(library, OrderRootType.CLASSES)) != null; + } + + @Nls + @Override + public String getLibraryVersion(@NotNull Library library, LibrariesContainer librariesContainer) { + return getGppVersion(librariesContainer.getLibraryFiles(library, OrderRootType.CLASSES)); + } + + @Nullable + private static String getGppVersion(VirtualFile[] files) { + for (VirtualFile file : files) { + Matcher matcher = GROOVYPP_JAR.matcher(file.getName()); + if (matcher.matches()) { + return matcher.group(1); + } + + matcher = GROOVYPP_ALL_JAR.matcher(file.getName()); + if (matcher.matches()) { + return matcher.group(1); + } + } + return null; + } + + @NotNull + @Override + public Icon getIcon() { + return GroovyIcons.GROOVY_ICON_16x16; + } + + @NotNull + @Override + public String getSDKVersion(String path) { + final VirtualFile file = LocalFileSystem.getInstance().findFileByPath(path); + assert file != null; + final VirtualFile libDir = file.findChild("lib"); + assert libDir != null; + final String version = getGppVersion(libDir.getChildren()); + if (version != null) { + return version; + } + throw new AssertionError(path); + } + + @NotNull + @Override + public String getAddActionText() { + return "Create new Groovy++ SDK..."; + } + + + @Nls + @NotNull + @Override + public String getLibraryCategoryName() { + return "GroovyPP"; + } + + @Override + public boolean isSDKHome(@NotNull VirtualFile file) { + final VirtualFile libDir = file.findChild("lib"); + return libDir != null && getGppVersion(libDir.getChildren()) != null; + } +} diff --git a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppStdLibSupport.java b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppStdLibSupport.java new file mode 100644 index 000000000000..c8e154d04d13 --- /dev/null +++ b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppStdLibSupport.java @@ -0,0 +1,116 @@ +package org.jetbrains.plugins.groovy.gpp; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.Key; +import com.intellij.psi.*; +import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.Function; +import com.intellij.util.NotNullFunction; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature; +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrGdkMethodImpl; +import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil; +import org.jetbrains.plugins.groovy.lang.resolve.DominanceAwareMethod; +import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersProcessor; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author peter + */ +public class GppStdLibSupport implements NonCodeMembersProcessor { + private static final Key>>> CACHED_STDLIB = Key.create("GppStdLib"); + private static final String[] STDLIB_CLASSES = { + "groovy.util.Conversions", + "groovy.util.Files", "groovy.util.Filters", + "groovy.util.Iterations", "groovy.util.Mappers", + "groovy.util.Sort", "groovy.util.Strings", + "groovy.util.With", + "org.mbte.groovypp.runtime.ArraysMethods", + "org.mbte.groovypp.runtime.DefaultGroovyPPMethods"}; + + public boolean processNonCodeMembers(PsiType type, PsiScopeProcessor processor, PsiElement place, boolean forCompletion) { + if (!(type instanceof PsiClassType)) { + return true; + } + if (!GppTypeConverter.hasTypedContext(place)) { + return true; + } + + final String className = TypeConversionUtil.erasure(type).getCanonicalText(); + + final Project project = place.getProject(); + final Map> map = CachedValuesManager.getManager(project).getCachedValue(project, CACHED_STDLIB, new CachedValueProvider>>() { + public Result>> compute() { + final GroovyPsiManager manager = GroovyPsiManager.getInstance(project); + final Map> result = new HashMap>(); + final NotNullFunction nonStaticConverter = new NotNullFunction() { + @NotNull + public PsiMethod fun(PsiMethod method) { + return new GppGdkMethod(method, false); + } + }; + + for (String qname : STDLIB_CLASSES) { + manager.addCategoryMethods(qname, result, nonStaticConverter); + } + + manager.addCategoryMethods("org.mbte.groovypp.runtime.DefaultGroovyPPStaticMethods", result, new NotNullFunction() { + @NotNull + public PsiMethod fun(PsiMethod method) { + return new GppGdkMethod(method, true); + } + }); + + return Result.create(result, ProjectRootManager.getInstance(project)); + } + }, false); + final List methods = map.get(className); + if (methods == null) { + return true; + } + + for (PsiMethod method : methods) { + if (!ResolveUtil.processElement(processor, method)) { + return false; + } + } + return true; + } + + private static class GppGdkMethod extends GrGdkMethodImpl implements DominanceAwareMethod { + public GppGdkMethod(PsiMethod method, final boolean isStatic) { + super(method, isStatic); + } + + public boolean dominates(@NotNull final PsiSubstitutor substitutor, + @NotNull PsiMethod another, + @NotNull PsiSubstitutor anotherSubstitutor, + @NotNull GroovyPsiElement context) { + if (another instanceof GrGdkMethodImpl && !(another instanceof GppGdkMethod) && another.getName().equals(getName())) { + final PsiType[] paramTypes = + ContainerUtil.map2Array(getParameterList().getParameters(), PsiType.class, new Function() { + public PsiType fun(PsiParameter psiParameter) { + return substitutor.substitute(psiParameter.getType()); + } + }); + final GrClosureSignature anotherSignature = GrClosureSignatureUtil.createSignature(another, anotherSubstitutor); + if (GrClosureSignatureUtil.isSignatureApplicable(anotherSignature, paramTypes, context)) { + return true; + } + } + return false; + } + } +} diff --git a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java new file mode 100644 index 000000000000..05444e29c495 --- /dev/null +++ b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java @@ -0,0 +1,125 @@ +package org.jetbrains.plugins.groovy.gpp; + +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.GrTypeConverter; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; +import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil; + +/** + * @author peter + */ +public class GppTypeConverter extends GrTypeConverter { + + public static boolean hasTypedContext(PsiElement context) { + return isTyped(PsiTreeUtil.getContextOfType(context, GrMember.class, true)); + } + + private static boolean isTyped(@Nullable PsiModifierListOwner member) { + if (member == null) { + return false; + } + + final PsiModifierList modifierList = member.getModifierList(); + if (modifierList != null && modifierList.findAnnotation("groovy.lang.Typed") != null) { + return true; + } + + final GrMember parentMember = PsiTreeUtil.getContextOfType(member, GrMember.class, true); + if (parentMember != null) { + return isTyped(parentMember); + } + + final PsiFile file = member.getContainingFile(); + if (file instanceof GroovyFile) { + final VirtualFile vfile = file.getVirtualFile(); + if (vfile != null) { + final String extension = vfile.getExtension(); + if ("gpp".equals(extension) || "grunit".equals(vfile.getExtension())) { + return true; + } + } + + return isTyped(JavaPsiFacade.getInstance(member.getProject()).findPackage(((GroovyFile)file).getPackageName())); + } + return false; + } + + @Override + public Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context) { + if (!hasTypedContext(context)) { + return null; + } + + + if (rType instanceof GrTupleType) { + final PsiType[] componentTypes = ((GrTupleType)rType).getComponentTypes(); + + final PsiType expectedComponent = PsiUtil.extractIterableTypeParameter(lType, false); + if (expectedComponent != null && hasDefaultConstructor(lType)) { + return true; + } + + if (lType instanceof PsiClassType && hasConstructor((PsiClassType)lType, componentTypes, context)) { + return true; + } + + return null; + } + else if (rType instanceof GrMapType) { + if (hasDefaultConstructor(lType)) { + return true; + } + + return null; + } + else if (rType instanceof GrClosureType) { + final PsiType[] methodParameters = GppClosureParameterTypeProvider.findSingleAbstractMethodSignature(lType); + final GrClosureSignature signature = ((GrClosureType)rType).getSignature(); + if (methodParameters != null && GrClosureSignatureUtil.isSignatureApplicable(signature, methodParameters, context)) { + return true; + } + return false; + } + + + return null; + } + + private static boolean hasDefaultConstructor(PsiType type) { + final PsiClass psiClass = PsiUtil.resolveClassInType(type); + return psiClass != null && PsiUtil.hasDefaultConstructor(psiClass, true); + + } + + private static boolean hasConstructor(PsiClassType lType, PsiType[] argTypes, GroovyPsiElement context) { + return getConstructorCandidates(lType, argTypes, context).length == 1; + } + + public static GroovyResolveResult[] getConstructorCandidates(PsiClassType classType, PsiType[] argTypes, GroovyPsiElement context) { + final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics(); + final PsiClass psiClass = resolveResult.getElement(); + final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + if (psiClass == null) { + return GroovyResolveResult.EMPTY_ARRAY; + } + + final GroovyResolveResult grResult = resolveResult instanceof GroovyResolveResult + ? (GroovyResolveResult)resolveResult + : new GroovyResolveResultImpl(psiClass, context, substitutor, true, true); + return org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getConstructorCandidates(context, new GroovyResolveResult[]{grResult}, argTypes); + } + +} diff --git a/plugins/groovy/hotswap/pluginSrc/META-INF/plugin.xml b/plugins/groovy/hotswap/pluginSrc/META-INF/plugin.xml index a14908dc40bd..973a4b192fcd 100644 --- a/plugins/groovy/hotswap/pluginSrc/META-INF/plugin.xml +++ b/plugins/groovy/hotswap/pluginSrc/META-INF/plugin.xml @@ -3,7 +3,7 @@ Groovy HotSwap Enables HotSwap functionality in Groovy classes 0.6 - + JetBrains Inc. org.intellij.groovy diff --git a/plugins/groovy/jetgroovy-tests.iml b/plugins/groovy/jetgroovy-tests.iml index 404e0345c714..da38fa97ebb1 100644 --- a/plugins/groovy/jetgroovy-tests.iml +++ b/plugins/groovy/jetgroovy-tests.iml @@ -25,6 +25,7 @@ +
    diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 8fc265d497d9..51426f1ca3e0 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -32,6 +32,8 @@ + + @@ -153,6 +155,8 @@ + + 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 485055cc628d..cb3c5dc8ee15 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -484,7 +484,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { public void visitConstructorInvocation(GrConstructorInvocation invocation) { final GroovyResolveResult resolveResult = invocation.resolveConstructorGenerics(); if (resolveResult != null && resolveResult.getElement() != null) { - checkMethodApplicability(resolveResult, invocation.getThisOrSuperKeyword(), myHolder); + checkMethodApplicability(resolveResult, invocation, myHolder); } else { final GroovyResolveResult[] results = invocation.multiResolveConstructor(); @@ -1179,7 +1179,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } - private static void checkMethodApplicability(GroovyResolveResult methodResolveResult, PsiElement place, AnnotationHolder holder) { + private static void checkMethodApplicability(GroovyResolveResult methodResolveResult, GroovyPsiElement place, AnnotationHolder holder) { final PsiElement element = methodResolveResult.getElement(); if (!(element instanceof PsiMethod)) return; @@ -1190,7 +1190,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { if (qualifierExpression != null) { final PsiType type = qualifierExpression.getType(); if (type instanceof GrClosureType) { - if (!PsiUtil.isApplicable(argumentTypes, (GrClosureType)type, element.getManager())) { + if (!PsiUtil.isApplicable(argumentTypes, (GrClosureType)type, place)) { highlightInapplicableMethodUsage(methodResolveResult, place, holder, method, argumentTypes); return; } @@ -1199,14 +1199,14 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } if (argumentTypes != null && !PsiUtil.isApplicable(argumentTypes, method, methodResolveResult.getSubstitutor(), - methodResolveResult.getCurrentFileResolveContext() instanceof GrMethodCallExpression)) { + methodResolveResult.getCurrentFileResolveContext() instanceof GrMethodCallExpression, place)) { //check for implicit use of property getter which returns closure if (GroovyPropertyUtils.isSimplePropertyGetter(method)) { if (method instanceof GrMethod || method instanceof GrAccessorMethod) { final PsiType returnType = PsiUtil.getSmartReturnType(method); if (returnType instanceof GrClosureType) { - if (PsiUtil.isApplicable(argumentTypes, ((GrClosureType)returnType), element.getManager())) { + if (PsiUtil.isApplicable(argumentTypes, ((GrClosureType)returnType), place)) { return; } } @@ -1216,7 +1216,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { if (returnType != null) { final PsiClassType closureType = JavaPsiFacade.getElementFactory(element.getProject()) .createTypeByFQClassName(GrClosableBlock.GROOVY_LANG_CLOSURE, GlobalSearchScope.allScope(element.getProject())); - if (TypesUtil.isAssignable(closureType, returnType, place.getManager(), place.getResolveScope())) { + if (TypesUtil.isAssignable(closureType, returnType, place)) { return; } } @@ -1320,7 +1320,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { if (nameElement instanceof GrExpression) { final PsiType stringType = JavaPsiFacade.getElementFactory(arg.getProject()).createTypeFromText(CommonClassNames.JAVA_LANG_STRING, arg); - if (!TypesUtil.isAssignable(stringType, ((GrExpression)nameElement).getType(), arg.getManager(), arg.getResolveScope())) { + if (!TypesUtil.isAssignable(stringType, ((GrExpression)nameElement).getType(), arg)) { holder.createWarningAnnotation(nameElement, GroovyBundle.message("property.name.expected")); } } @@ -1348,7 +1348,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } - private static void checkClosureApplicability(GroovyResolveResult resolveResult, PsiType type, PsiElement place, AnnotationHolder holder) { + private static void checkClosureApplicability(GroovyResolveResult resolveResult, PsiType type, GroovyPsiElement place, AnnotationHolder holder) { final PsiElement element = resolveResult.getElement(); if (!(element instanceof GrVariable)) return; if (!(type instanceof GrClosureType)) return; @@ -1356,7 +1356,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { PsiType[] argumentTypes = PsiUtil.getArgumentTypes(place, true); if (argumentTypes == null) return; - if (PsiUtil.isApplicable(argumentTypes, (GrClosureType)type, element.getManager())) return; + if (PsiUtil.isApplicable(argumentTypes, (GrClosureType)type, place)) return; final String typesString = buildArgTypesList(argumentTypes); String message = GroovyBundle.message("cannot.apply.method.or.closure", variable.getName(), typesString); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GroovyStaticImportMethodFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GroovyStaticImportMethodFix.java index 2ae66ac4dc1b..969502dffb46 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GroovyStaticImportMethodFix.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GroovyStaticImportMethodFix.java @@ -129,7 +129,7 @@ public class GroovyStaticImportMethodFix implements IntentionAction { //do not show methods from default package && ((PsiClassOwner)file).getPackageName().length() != 0 && PsiUtil.isAccessible(element, method)) { list.add(method); - if (PsiUtil.isApplicable(PsiUtil.getArgumentTypes(element, true), method, PsiSubstitutor.EMPTY, false)) { + if (PsiUtil.isApplicable(PsiUtil.getArgumentTypes(element, true), method, PsiSubstitutor.EMPTY, false, element)) { applicableList.add(method); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java index 4acea75b2082..694805402df8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java @@ -78,7 +78,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { if (PsiUtil.isRawClassMemberAccess(expression)) return; //GRVY-2197 final PsiType rType = expression.getType(); if (rType == null || rType == PsiType.VOID) return; - if (!TypesUtil.isAssignable(expectedType, rType, element.getManager(), element.getResolveScope())) { + if (!TypesUtil.isAssignable(expectedType, rType, element)) { registerError(element, rType.getPresentableText(), expectedType.getPresentableText()); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyUncheckedAssignmentOfMemberOfRawTypeInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyUncheckedAssignmentOfMemberOfRawTypeInspection.java index c229fd533278..28617967ab7f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyUncheckedAssignmentOfMemberOfRawTypeInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyUncheckedAssignmentOfMemberOfRawTypeInspection.java @@ -26,6 +26,7 @@ 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.lang.lexer.GroovyTokenTypes; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; @@ -168,10 +169,10 @@ public class GroovyUncheckedAssignmentOfMemberOfRawTypeInspection extends BaseIn } } - private void checkAssignability(PsiType lType, GrExpression rExpr, PsiElement element) { + private void checkAssignability(PsiType lType, GrExpression rExpr, GroovyPsiElement element) { if (PsiUtil.isRawClassMemberAccess(rExpr)) { final PsiType rType = rExpr.getType(); - if (!TypesUtil.isAssignable(lType, rType, element.getManager(), element.getResolveScope())) { + if (!TypesUtil.isAssignable(lType, rType, element)) { registerError(element, lType, rType); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyListGetCanBeKeyedAccessInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyListGetCanBeKeyedAccessInspection.java index 54896e7c2345..5d0781726489 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyListGetCanBeKeyedAccessInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyListGetCanBeKeyedAccessInspection.java @@ -19,6 +19,7 @@ import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -26,7 +27,6 @@ import org.jetbrains.annotations.Nullable; 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.utils.ClassUtils; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; @@ -110,10 +110,10 @@ public class GroovyListGetCanBeKeyedAccessInspection extends BaseInspection { return; } final PsiType type = qualifier.getType(); - if (!ClassUtils.isSubclass(type, "java.util.List")) { + if (!InheritanceUtil.isInheritor(type, "java.util.List")) { return; } registerMethodCallError(grMethodCallExpression); } } -} \ No newline at end of file +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyListSetCanBeKeyedAccessInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyListSetCanBeKeyedAccessInspection.java index d2135ebfe3fd..a25ee2b7a745 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyListSetCanBeKeyedAccessInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyListSetCanBeKeyedAccessInspection.java @@ -19,6 +19,7 @@ import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -26,7 +27,6 @@ import org.jetbrains.annotations.Nullable; 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.utils.ClassUtils; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; @@ -111,10 +111,10 @@ public class GroovyListSetCanBeKeyedAccessInspection extends BaseInspection { return; } final PsiType type = qualifier.getType(); - if (!ClassUtils.isSubclass(type, "java.util.List")) { + if (!InheritanceUtil.isInheritor(type, "java.util.List")) { return; } registerMethodCallError(grMethodCallExpression); } } -} \ No newline at end of file +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyMapGetCanBeKeyedAccessInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyMapGetCanBeKeyedAccessInspection.java index 2247a8cee218..44d061efd7fb 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyMapGetCanBeKeyedAccessInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyMapGetCanBeKeyedAccessInspection.java @@ -19,6 +19,7 @@ import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -26,7 +27,6 @@ import org.jetbrains.annotations.Nullable; 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.utils.ClassUtils; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; @@ -110,10 +110,10 @@ public class GroovyMapGetCanBeKeyedAccessInspection extends BaseInspection { return; } final PsiType type = qualifier.getType(); - if (!ClassUtils.isSubclass(type, "java.util.Map")) { + if (!InheritanceUtil.isInheritor(type, "java.util.Map")) { return; } registerMethodCallError(grMethodCallExpression); } } -} \ No newline at end of file +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyMapPutCanBeKeyedAccessInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyMapPutCanBeKeyedAccessInspection.java index ab6cce3c8e66..c12d5b64ba2b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyMapPutCanBeKeyedAccessInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/gpath/GroovyMapPutCanBeKeyedAccessInspection.java @@ -19,6 +19,7 @@ import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -26,7 +27,6 @@ import org.jetbrains.annotations.Nullable; 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.utils.ClassUtils; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; @@ -112,10 +112,10 @@ public class GroovyMapPutCanBeKeyedAccessInspection extends BaseInspection { return; } final PsiType type = qualifier.getType(); - if (!ClassUtils.isSubclass(type, "java.util.Map")) { + if (!InheritanceUtil.isInheritor(type, "java.util.Map")) { return; } registerMethodCallError(grMethodCallExpression); } } -} \ No newline at end of file +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ClassUtils.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ClassUtils.java deleted file mode 100644 index 90f3378a21b3..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ClassUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2007-2008 Dave Griffith - * - * 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.utils; - -import com.intellij.openapi.project.Project; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiClassType; -import com.intellij.psi.PsiType; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.InheritanceUtil; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.Nullable; - -public class ClassUtils { - - public static boolean isSubclass(@Nullable PsiType type, - @NonNls String ancestorName) { - if (type == null) { - return false; - } - if (!(type instanceof PsiClassType)) { - return false; - } - PsiClassType classType = (PsiClassType) type; - final PsiClass aClass = classType.resolve(); - return isSubclass(aClass, ancestorName); - } - - public static boolean isSubclass(@Nullable PsiClass aClass, - @NonNls String ancestorName) { - if (aClass == null) { - return false; - } - final Project project = aClass.getProject(); - final GlobalSearchScope scope = GlobalSearchScope.allScope(project); - final PsiClass ancestorClass = JavaPsiFacade.getInstance(aClass.getProject()).findClass(ancestorName, scope); - return InheritanceUtil.isCorrectDescendant(aClass, ancestorClass, true); - } -} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java index 19749946b1b5..04b2540df6e7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java @@ -95,10 +95,6 @@ public class GroovyToJavaGenerator { PsiModifier.ABSTRACT, PsiModifier.FINAL, PsiModifier.NATIVE, - PsiModifier.SYNCHRONIZED, - PsiModifier.STRICTFP, - PsiModifier.TRANSIENT, - PsiModifier.VOLATILE }; private static final CharSequence PREFIX_SEPARATOR = "/"; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java index cc4d1491e3a2..791908cfa842 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java @@ -288,11 +288,17 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { if (cause instanceof ProcessCanceledException) { throw (ProcessCanceledException)cause; } + if (cause instanceof OutOfMemoryError) { + throw (OutOfMemoryError)cause; + } handleDslError(e, project, dslFile); } catch (ProcessCanceledException e) { throw e; } + catch (OutOfMemoryError e) { + throw e; + } catch (Throwable e) { // To handle exceptions in definition script handleDslError(e, project, dslFile); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/selection/GroovyBlockStatementsSelectioner.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/selection/GroovyBlockStatementsSelectioner.java index 0ad71eca17f4..d264fbd01278 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/selection/GroovyBlockStatementsSelectioner.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/selection/GroovyBlockStatementsSelectioner.java @@ -19,7 +19,7 @@ package org.jetbrains.plugins.groovy.editor.selection; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock; import java.util.List; @@ -37,17 +37,37 @@ public class GroovyBlockStatementsSelectioner extends GroovyBasicSelectioner { List result = super.select(e, editorText, cursorOffset, editor); if (e instanceof GrCodeBlock) { - GrCodeBlock block = ((GrCodeBlock) e); - GrStatement[] statements = block.getStatements(); - - if (statements.length > 0) { - int startOffset = statements[0].getTextRange().getStartOffset(); - int endOffset = statements[statements.length - 1].getTextRange().getEndOffset(); - TextRange range = new TextRange(startOffset, endOffset); - result.add(range); - } + GrCodeBlock block = ((GrCodeBlock)e); + int startOffset = findOpeningBrace(block); + int endOffset = findClosingBrace(block, startOffset); + TextRange range = new TextRange(startOffset, endOffset); + result.addAll(expandToWholeLine(editorText, range)); } return result; } + private static int findOpeningBrace(GrCodeBlock block) { + PsiElement lbrace = block.getLBrace(); + if (lbrace == null) return block.getTextRange().getStartOffset(); + + while (isWhiteSpace(lbrace.getNextSibling())) { + lbrace = lbrace.getNextSibling(); + } + return lbrace.getTextRange().getEndOffset(); + } + + private static int findClosingBrace(GrCodeBlock block, int startOffset) { + PsiElement rbrace = block.getRBrace(); + if (rbrace == null) return block.getTextRange().getEndOffset(); + + while (isWhiteSpace(rbrace.getPrevSibling()) && rbrace.getPrevSibling().getTextRange().getStartOffset() > startOffset) { + rbrace = rbrace.getPrevSibling(); + } + + return rbrace.getTextRange().getStartOffset(); + } + + private static boolean isWhiteSpace(PsiElement element) { + return element != null && GroovyTokenTypes.WHITE_SPACES_SET.contains(element.getNode().getElementType()); + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/GroovyBlockGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/GroovyBlockGenerator.java index 12a23d5dc015..5aee613507e2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/GroovyBlockGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/GroovyBlockGenerator.java @@ -121,7 +121,7 @@ public class GroovyBlockGenerator implements GroovyElementTypes { final ArrayList subBlocks = new ArrayList(); ASTNode[] children = node.getChildren(null); ASTNode prevChildNode = null; - final Alignment alignment = mustAlign(blockPsi, mySettings) ? Alignment.createAlignment() : null; + final Alignment alignment = mustAlign(blockPsi, mySettings, children) ? Alignment.createAlignment() : null; for (ASTNode childNode : children) { if (canBeCorrectBlock(childNode)) { final Indent indent = GroovyIndentProcessor.getChildIndent(block, prevChildNode, childNode); @@ -146,12 +146,33 @@ public class GroovyBlockGenerator implements GroovyElementTypes { return subBlocks; } - private static boolean mustAlign(PsiElement blockPsi, CodeStyleSettings mySettings) { + private static boolean mustAlign(PsiElement blockPsi, CodeStyleSettings mySettings, ASTNode[] children) { + // We don't want to align single call argument if it's a closure. The reason is that it looks better to have call like + // + // foo({ + // println 'xxx' + // }) + // + // than + // + // foo({ + // println 'xxx' + // }) + if (blockPsi instanceof GrArgumentList && mySettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS) { + List nonWhiteSpaceNodes = new ArrayList(); + for (ASTNode child : children) { + if (!WHITE_SPACES_OR_COMMENTS.contains(child.getElementType())) { + nonWhiteSpaceNodes.add(child); + } + } + return nonWhiteSpaceNodes.size() != 3 || nonWhiteSpaceNodes.get(0).getElementType() != mLPAREN + || nonWhiteSpaceNodes.get(1).getElementType() != CLOSABLE_BLOCK || nonWhiteSpaceNodes.get(2).getElementType() != mRPAREN; + } + return blockPsi instanceof GrParameterList && mySettings.ALIGN_MULTILINE_PARAMETERS || blockPsi instanceof GrExtendsClause && mySettings.ALIGN_MULTILINE_EXTENDS_LIST || blockPsi instanceof GrThrowsClause && mySettings.ALIGN_MULTILINE_THROWS_LIST || - blockPsi instanceof GrConditionalExpression && mySettings.ALIGN_MULTILINE_TERNARY_OPERATION || - blockPsi instanceof GrArgumentList && mySettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS; + blockPsi instanceof GrConditionalExpression && mySettings.ALIGN_MULTILINE_TERNARY_OPERATION; } private static boolean isListLikeClause(PsiElement blockPsi) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/IndexingMethodConversionPredicate.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/IndexingMethodConversionPredicate.java index 8e0564dd5a2c..ea88baeaba19 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/IndexingMethodConversionPredicate.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/IndexingMethodConversionPredicate.java @@ -15,13 +15,11 @@ */ package org.jetbrains.plugins.groovy.intentions.conversions; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.CommonClassNames; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.intentions.base.ErrorUtil; import org.jetbrains.plugins.groovy.intentions.base.PsiElementPredicate; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; @@ -83,26 +81,7 @@ class IndexingMethodConversionPredicate implements PsiElementPredicate { } private static boolean isMap(PsiType type) { - if (type == null) { - return false; - } - if (!(type instanceof PsiClassType)) { - return false; - } - final PsiClass referentClass = ((PsiClassType) type).resolve(); - return isSubclass(referentClass, "java.util.Map"); - } - - public static boolean isSubclass(@Nullable PsiClass aClass, - @NonNls String ancestorName) { - if (aClass == null) { - return false; - } - final JavaPsiFacade facade = JavaPsiFacade.getInstance(aClass.getProject()); - final Project project = facade.getProject(); - final GlobalSearchScope scope = GlobalSearchScope.allScope(project); - final PsiClass ancestorClass = facade.findClass(ancestorName, scope); - return InheritanceUtil.isCorrectDescendant(aClass, ancestorClass, true); + return InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parameterInfo/GroovyParameterInfoHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parameterInfo/GroovyParameterInfoHandler.java index 0382bb84c211..f4b560bddc5f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parameterInfo/GroovyParameterInfoHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parameterInfo/GroovyParameterInfoHandler.java @@ -20,7 +20,9 @@ import com.intellij.codeInsight.completion.JavaCompletionUtil; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.lang.parameterInfo.*; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; @@ -28,25 +30,23 @@ import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.documentation.GroovyPresentationUtil; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import java.util.ArrayList; import java.util.List; @@ -114,31 +114,7 @@ public class GroovyParameterInfoHandler implements ParameterInfoHandler namedElements = ContainerUtil.findAll(variants, new Condition() { public boolean value(GroovyResolveResult groovyResolveResult) { return groovyResolveResult.getElement() instanceof PsiNamedElement; @@ -148,14 +124,6 @@ public class GroovyParameterInfoHandler implements ParameterInfoHandler 0 ? 1 : 0; final GrExpression[] exprs = list.getExpressionArguments(); for (GrExpression expr : exprs) { - if (expr.getTextRange().contains(offset)) return idx; + if (getArgRange(expr).contains(offset)) return idx; idx++; } + + if (exprs.length == 0 || getArgRange(exprs[exprs.length - 1]).getEndOffset() <= offset) { + return idx; + } + else { + return 0; + } } return -1; } + private static TextRange getArgRange(PsiElement arg) { + PsiElement cur = arg; + int end; + int start; + do { + PsiElement sibling = cur.getNextSibling(); + if (sibling == null) { + end = cur.getTextRange().getEndOffset(); + break; + } + else { + cur = sibling; + } + IElementType type = cur.getNode().getElementType(); + if (GroovyTokenTypes.mCOMMA.equals(type) || GroovyTokenTypes.mRPAREN.equals(type)) { + end = cur.getTextRange().getStartOffset(); + break; + } + } + while (true); + + do { + PsiElement sibling = cur.getPrevSibling(); + if (sibling == null) { + start = cur.getTextRange().getStartOffset(); + break; + } + else { + cur = sibling; + } + IElementType type = cur.getNode().getElementType(); + if (GroovyTokenTypes.mCOMMA.equals(type) || GroovyTokenTypes.mLPAREN.equals(type)) { + start = cur.getTextRange().getEndOffset(); + break; + } + } + while (true); + + return new TextRange(start, end + 1); + } + public String getParameterCloseChars() { return ",){}"; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/AbstractClosureParameterEnhancer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/AbstractClosureParameterEnhancer.java new file mode 100644 index 000000000000..d1669a4181b8 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/AbstractClosureParameterEnhancer.java @@ -0,0 +1,50 @@ +package org.jetbrains.plugins.groovy.lang.psi; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +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.params.GrParameter; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterList; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.ClosureSyntheticParameter; + +import java.util.Arrays; + +/** + * @author peter + */ +public abstract class AbstractClosureParameterEnhancer extends GrVariableEnhancer { + @Override + public PsiType getVariableType(GrVariable variable) { + if (!(variable instanceof GrParameter)) { + return null; + } + + GrClosableBlock closure = variable instanceof ClosureSyntheticParameter + ? ((ClosureSyntheticParameter)variable).getClosure() : findClosureWithArgument(variable.getParent()); + if (closure == null) { + return null; + } + + @SuppressWarnings({"SuspiciousMethodCalls"}) + int index = Arrays.asList(closure.getAllParameters()).indexOf(variable); + assert index >= 0; + return getClosureParameterType(closure, index); + } + + @Nullable + private static GrClosableBlock findClosureWithArgument(@NotNull PsiElement parent) { + if (parent instanceof GrParameterList) { + GrParameterList list = (GrParameterList)parent; + if (list.getParent() instanceof GrClosableBlock) { + return (GrClosableBlock)list.getParent(); + } + } + return null; + } + + @Nullable + protected abstract PsiType getClosureParameterType(GrClosableBlock closure, int index); +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/ClosureParameterEnhancer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/ClosureParameterEnhancer.java index 7b32c77745c8..50ddc7147682 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/ClosureParameterEnhancer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/ClosureParameterEnhancer.java @@ -5,70 +5,33 @@ import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -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.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrParenthesizedExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.arithmetic.GrRangeExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterList; import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; -import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.ClosureSyntheticParameter; - -import java.util.Arrays; /** * @author peter */ -public class ClosureParameterEnhancer extends GrVariableEnhancer { - @Override - public PsiType getVariableType(GrVariable variable) { - if (!(variable instanceof GrParameter)) { - return null; - } +public class ClosureParameterEnhancer extends AbstractClosureParameterEnhancer { - GrClosableBlock closure = variable instanceof ClosureSyntheticParameter ? ((ClosureSyntheticParameter)variable).getClosure() : findClosureWithArgument(variable.getParent()); - if (closure == null) { - return null; - } + @Override + @Nullable + protected PsiType getClosureParameterType(GrClosableBlock closure, int index) { final PsiElement parent = closure.getParent(); if (!(parent instanceof GrMethodCallExpression)) { return null; } - - final PsiParameter[] parameters = closure.getAllParameters(); - @SuppressWarnings({"SuspiciousMethodCalls"}) - int index = Arrays.asList(parameters).indexOf(variable); - assert index >= 0; - - return findClosureParameterType(closure, index, variable, (GrMethodCallExpression)parent, parameters.length); - } - - @Nullable - private static GrClosableBlock findClosureWithArgument(@NotNull PsiElement parent) { - if (parent instanceof GrParameterList) { - GrParameterList list = (GrParameterList)parent; - if (list.getParent() instanceof GrClosableBlock) { - return (GrClosableBlock)list.getParent(); - } - } - return null; - } - - - @Nullable - private static PsiType findClosureParameterType(@NotNull GrClosableBlock closure, - int index, PsiElement context, - final GrMethodCallExpression methodCall, int paramCount) { PsiElementFactory factory = JavaPsiFacade.getInstance(closure.getProject()).getElementFactory(); - String methodName = findMethodName(methodCall); + String methodName = findMethodName((GrMethodCallExpression)parent); //final GrExpression invokedExpression = methodCall.getInvokedExpression(); //PsiType type = findQualifierType(methodCall); - GrExpression expression = methodCall.getInvokedExpression(); + GrExpression expression = ((GrMethodCallExpression)parent).getInvokedExpression(); if (!(expression instanceof GrReferenceExpression)) return null; GrExpression qualifier = ((GrReferenceExpression)expression).getQualifierExpression(); @@ -85,14 +48,14 @@ public class ClosureParameterEnhancer extends GrVariableEnhancer { "find".equals(methodName) || "findAll".equals(methodName) || "findIndexOf".equals(methodName)) { - PsiType res = findTypeForCollection(qualifier, factory, context); + PsiType res = findTypeForCollection(qualifier, factory, closure); if (closure.getParameters().length <= 1 && res != null) { return res; } if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) { if (closure.getParameters().length <= 1) { - return getEntryForMap(type, factory, context); + return getEntryForMap(type, factory, closure); } if (closure.getParameters().length == 2) { if (index == 0) { @@ -105,48 +68,52 @@ public class ClosureParameterEnhancer extends GrVariableEnhancer { else if ("with".equals(methodName) && closure.getParameters().length <= 1) { return type; } - else if ("eachWithIndex".equals(methodName)) { - PsiType res = findTypeForCollection(qualifier, factory, context); - if (closure.getParameters().length == 2 && res != null) { + else { + final PsiParameter[] paramCount = closure.getAllParameters(); + if ("eachWithIndex".equals(methodName)) { + PsiType res = findTypeForCollection(qualifier, factory, closure); + if (closure.getParameters().length == 2 && res != null) { + if (index == 0) { + return res; + } + return factory.createTypeFromText(CommonClassNames.JAVA_LANG_INTEGER, closure); + } + if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) { + if (paramCount.length == 2) { + if (index == 0) { + return getEntryForMap(type, factory, closure); + } + return factory.createTypeFromText(CommonClassNames.JAVA_LANG_INTEGER, closure); + } + if (paramCount.length == 3) { + if (index == 0) { + return PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_UTIL_MAP, 0, true); + } + if (index == 1) { + return PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_UTIL_MAP, 1, true); + } + return factory.createTypeFromText(CommonClassNames.JAVA_LANG_INTEGER, closure); + } + } + } + else if ("inject".equals(methodName) && paramCount.length == 2) { if (index == 0) { + return factory.createTypeFromText(CommonClassNames.JAVA_LANG_OBJECT, closure); + } + + PsiType res = findTypeForCollection(qualifier, factory, closure); + if (res != null) { return res; } - return factory.createTypeFromText(CommonClassNames.JAVA_LANG_INTEGER, context); - } - if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) { - if (paramCount == 2) { - if (index == 0) { - return getEntryForMap(type, factory, context); - } - return factory.createTypeFromText(CommonClassNames.JAVA_LANG_INTEGER, context); + if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) { + return getEntryForMap(type, factory, closure); } - if (paramCount == 3) { - if (index == 0) { - return PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_UTIL_MAP, 0, true); - } - if (index == 1) { - return PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_UTIL_MAP, 1, true); - } - return factory.createTypeFromText(CommonClassNames.JAVA_LANG_INTEGER, context); - } - } - } - else if ("inject".equals(methodName) && paramCount == 2) { - if (index == 0) { - return factory.createTypeFromText(CommonClassNames.JAVA_LANG_OBJECT, context); - } - - PsiType res = findTypeForCollection(qualifier, factory, context); - if (res != null) { - return res; - } - if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) { - return getEntryForMap(type, factory, context); } } return null; } + @Nullable private static PsiType getEntryForMap(PsiType map, PsiElementFactory factory, PsiElement context) { PsiType key = PsiUtil.substituteTypeParameter(map, CommonClassNames.JAVA_UTIL_MAP, 0, true); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrClassSubstitution.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrClassSubstitution.java new file mode 100644 index 000000000000..0ee49ec1bbe7 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrClassSubstitution.java @@ -0,0 +1,9 @@ +package org.jetbrains.plugins.groovy.lang.psi; + +import com.intellij.psi.PsiClass; + +/** + * @author peter + */ +public interface GrClassSubstitution extends PsiClass { +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrClassSubstitutor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrClassSubstitutor.java new file mode 100644 index 000000000000..c8196595ff3b --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrClassSubstitutor.java @@ -0,0 +1,48 @@ +package org.jetbrains.plugins.groovy.lang.psi; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.util.Key; +import com.intellij.psi.PsiClass; +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author peter + */ +public abstract class GrClassSubstitutor { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("org.intellij.groovy.classSubstitutor"); + private static final Key> SUBSTITUTED_CLASS_KEY = Key.create("GroovySubstitutedType"); + + @Nullable + public abstract GrClassSubstitution substituteClass(@NotNull PsiClass base); + + @NotNull + public static PsiClass getSubstitutedClass(@NotNull final PsiClass base) { + if (!Extensions.getRootArea().getExtensionPoint(EP_NAME).hasAnyExtensions()) { + return base; + } + + if (base instanceof GrClassSubstitution) { + return base; + } + + return CachedValuesManager.getManager(base.getProject()) + .getCachedValue(base, SUBSTITUTED_CLASS_KEY, new CachedValueProvider() { + public Result compute() { + for (GrClassSubstitutor enhancer : GrClassSubstitutor.EP_NAME.getExtensions()) { + final PsiClass type = enhancer.substituteClass(base); + if (type != null) { + return Result.create(type, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + } + } + return Result.create(base, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + } + }, false); + } + +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java index de52ac635dd7..3fdc0239b076 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java @@ -1,9 +1,8 @@ package org.jetbrains.plugins.groovy.lang.psi; import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.psi.PsiManager; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; -import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,6 +13,6 @@ public abstract class GrTypeConverter { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("org.intellij.groovy.typeConverter"); @Nullable - public abstract Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, PsiManager manager, GlobalSearchScope scope); + public abstract Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context); } \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyDeclarationSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyDeclarationSearcher.java new file mode 100644 index 000000000000..d3e77699f03b --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyDeclarationSearcher.java @@ -0,0 +1,23 @@ +package org.jetbrains.plugins.groovy.lang.psi; + +import com.intellij.pom.PomDeclarationSearcher; +import com.intellij.pom.PomTarget; +import com.intellij.psi.PsiElement; +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; + +/** + * @author peter + */ +public class GroovyDeclarationSearcher extends PomDeclarationSearcher { + @Override + public void findDeclarationsAt(@NotNull PsiElement element, int offsetInElement, Consumer consumer) { + if (element instanceof GrTypeDefinition) { + final PsiElement name = ((GrTypeDefinition)element).getNameIdentifierGroovy(); + if (name.getTextRange().shiftRight(-element.getTextRange().getStartOffset()).contains(offsetInElement)) { + consumer.consume(GrClassSubstitutor.getSubstitutedClass((GrTypeDefinition)element)); + } + } + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyElementVisitor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyElementVisitor.java index 4dd9df9bbdcb..1d1adfae75bb 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyElementVisitor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyElementVisitor.java @@ -133,7 +133,7 @@ public abstract class GroovyElementVisitor { } public void visitCommandArguments(GrCommandArgumentList argumentList) { - visitElement(argumentList); + visitArgumentList(argumentList); } public void visitConditionalExpression(GrConditionalExpression expression) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/arguments/GrArgumentLabel.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/arguments/GrArgumentLabel.java index cb703dcfadc2..a53fe05201d2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/arguments/GrArgumentLabel.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/arguments/GrArgumentLabel.java @@ -39,5 +39,8 @@ public interface GrArgumentLabel extends GroovyPsiElement, PsiReference { @Nullable PsiType getExpectedArgumentType(); + @Nullable + PsiType getLabelType(); + GrNamedArgument getNamedArgument(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesContributor.java new file mode 100644 index 000000000000..5932d1e14357 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesContributor.java @@ -0,0 +1,16 @@ +package org.jetbrains.plugins.groovy.lang.psi.expectedTypes; + +import com.intellij.openapi.extensions.ExtensionPointName; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; + +import java.util.List; + +/** + * @author peter + */ +public abstract class GroovyExpectedTypesContributor { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("org.intellij.groovy.expectedTypesContributor"); + + public abstract List calculateTypeConstraints(@NotNull GrExpression expression); +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java index ed726ad77086..8e6af987e71b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java @@ -18,29 +18,27 @@ package org.jetbrains.plugins.groovy.lang.psi.expectedTypes; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrIfStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrWhileStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrTraditionalForClause; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; -import java.util.ArrayList; -import java.util.List; +import java.util.*; /** * @author ven @@ -52,7 +50,27 @@ public class GroovyExpectedTypesProvider { public static TypeConstraint[] calculateTypeConstraints(GrExpression expression) { MyCalculator calculator = new MyCalculator(expression); ((GroovyPsiElement)expression.getParent()).accept(calculator); - return calculator.getResult(); + final TypeConstraint[] result = calculator.getResult(); + + List custom = new ArrayList(); + for (GroovyExpectedTypesContributor contributor : GroovyExpectedTypesContributor.EP_NAME.getExtensions()) { + custom.addAll(contributor.calculateTypeConstraints(expression)); + } + + if (!custom.isEmpty()) { + custom.addAll(0, Arrays.asList(result)); + return custom.toArray(new TypeConstraint[custom.size()]); + } + + return result; + } + + public static Set getDefaultExpectedTypes(GrExpression element) { + final LinkedHashSet result = new LinkedHashSet(); + for (TypeConstraint constraint : calculateTypeConstraints(element)) { + result.add(constraint.getDefaultType()); + } + return result; } @@ -86,8 +104,37 @@ public class GroovyExpectedTypesProvider { } public void visitMethodCallExpression(GrMethodCallExpression methodCall) { - if (myExpression.equals(methodCall.getInvokedExpression())) { + final GrExpression invokedExpression = methodCall.getInvokedExpression(); + if (myExpression.equals(invokedExpression)) { myResult = new TypeConstraint[]{SubtypeConstraint.create("groovy.lang.Closure", methodCall)}; + return; + } + //noinspection SuspiciousMethodCalls + if (Arrays.asList(methodCall.getClosureArguments()).contains(myExpression)) { + List constraints = new ArrayList(); + for (GroovyResolveResult variant : methodCall.getMethodVariants()) { + PsiParameter[] parameters = getCallParameters(variant); + if (parameters == null || parameters.length == 0) continue; + + constraints.add(SubtypeConstraint.create(variant.getSubstitutor().substitute(parameters[parameters.length - 1].getType()))); + } + if (!constraints.isEmpty()) { + myResult = constraints.toArray(new TypeConstraint[constraints.size()]); + } + + } + } + + @Override + public void visitOpenBlock(GrOpenBlock block) { + if (block.getParent() instanceof PsiMethod) { + final GrStatement[] statements = block.getStatements(); + if (statements.length > 0 && myExpression.equals(statements[statements.length - 1])) { + final PsiType type = ((PsiMethod)block.getParent()).getReturnType(); + if (type != null) { + myResult = new TypeConstraint[]{new SubtypeConstraint(type, type)}; + } + } } } @@ -110,31 +157,32 @@ public class GroovyExpectedTypesProvider { } public void visitArgumentList(GrArgumentList list) { - PsiElement parent = list.getParent(); - List constraints = new ArrayList(); - if (parent instanceof GrCallExpression) { - GroovyResolveResult[] variants = ((GrCallExpression)parent).getMethodVariants(); - int idx = list.getExpressionArgumentIndex(myExpression); - for (GroovyResolveResult variant : variants) { - PsiElement element = variant.getElement(); - PsiParameter[] parameters = null; - if (element instanceof GrParametersOwner) { - parameters = ((GrParametersOwner)element).getParameters(); - } - else if (element instanceof PsiMethod) { - parameters = ((PsiMethod)element).getParameterList().getParameters(); - } - if (parameters == null || parameters.length <= idx) continue; - PsiType parameterType = variant.getSubstitutor().substitute(parameters[idx].getType()); - constraints.add(SubtypeConstraint.create(parameterType)); - } - } + int idx = list.getExpressionArgumentIndex(myExpression); + List constraints = new ArrayList(); + for (GroovyResolveResult variant : ResolveUtil.getMethodVariants(list)) { + PsiParameter[] parameters = getCallParameters(variant); + if (parameters == null || parameters.length <= idx) continue; + PsiType parameterType = variant.getSubstitutor().substitute(parameters[idx].getType()); + constraints.add(SubtypeConstraint.create(parameterType)); + } if (!constraints.isEmpty()) { myResult = constraints.toArray(new TypeConstraint[constraints.size()]); } } + @Nullable + private static PsiParameter[] getCallParameters(GroovyResolveResult variant) { + PsiElement element = variant.getElement(); + if (element instanceof GrParametersOwner) { + return ((GrParametersOwner)element).getParameters(); + } + else if (element instanceof PsiMethod) { + return ((PsiMethod)element).getParameterList().getParameters(); + } + return null; + } + public void visitAssignmentExpression(GrAssignmentExpression expression) { GrExpression rValue = expression.getRValue(); if (myExpression.equals(rValue)) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java new file mode 100644 index 000000000000..acdf25e089ca --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java @@ -0,0 +1,137 @@ +package org.jetbrains.plugins.groovy.lang.psi.impl; + +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; + +/** + * @author peter + */ +public abstract class GrLiteralClassType extends PsiClassType { + protected final GlobalSearchScope myScope; + protected final JavaPsiFacade myFacade; + + public GrLiteralClassType(LanguageLevel languageLevel, GlobalSearchScope scope, JavaPsiFacade facade) { + super(languageLevel); + myScope = scope; + myFacade = facade; + } + + protected abstract String getJavaClassName(); + + @NotNull + public ClassResolveResult resolveGenerics() { + return new ClassResolveResult() { + private final PsiClass myBaseClass = resolve(); + + public PsiClass getElement() { + return myBaseClass; + } + + public PsiSubstitutor getSubstitutor() { + PsiSubstitutor result = PsiSubstitutor.EMPTY; + if (myBaseClass != null) { + final PsiType[] typeArgs = getParameters(); + final PsiTypeParameter[] typeParams = myBaseClass.getTypeParameters(); + if (typeParams.length == typeArgs.length) { + for (int i = 0; i < typeArgs.length; i++) { + result = result.put(typeParams[i], typeArgs[i]); + } + } + } + return result; + } + + public boolean isPackagePrefixPackageReference() { + return false; + } + + public boolean isAccessible() { + return true; + } + + public boolean isStaticsScopeCorrect() { + return true; + } + + public PsiElement getCurrentFileResolveScope() { + return null; + } + + public boolean isValidResult() { + return isStaticsScopeCorrect() && isAccessible(); + } + }; + } + + public String getPresentableText() { + return getClassName(); + } + + @Nullable + public String getCanonicalText() { + PsiClass resolved = resolve(); + if (resolved == null) return null; + return resolved.getQualifiedName(); + } + + @NotNull + public LanguageLevel getLanguageLevel() { + return myLanguageLevel; + } + + public GlobalSearchScope getScope() { + return myScope; + } + + @Nullable + public PsiClass resolve() { + return myFacade.findClass(getJavaClassName(), getResolveScope()); + } + + @NotNull + public PsiClassType rawType() { + return myFacade.getElementFactory().createTypeByFQClassName(getJavaClassName(), myScope); + } + + public boolean equalsToText(@NonNls String text) { + return text.equals(getJavaClassName()); + } + + @NotNull + public GlobalSearchScope getResolveScope() { + return myScope; + } + + protected static String getInternalCanonicalText(@Nullable PsiType type) { + return type == null ? CommonClassNames.JAVA_LANG_OBJECT : type.getInternalCanonicalText(); + } + + @Nullable + private static PsiType getLeastUpperBound(@Nullable PsiType result, @Nullable PsiType other, PsiManager manager) { + if (other == null) return result; + if (result == null) result = other; + if (result.isAssignableFrom(other)) return result; + if (other.isAssignableFrom(result)) result = other; + + return TypesUtil.getLeastUpperBound(result, other, manager); + } + + @NotNull + protected PsiType getLeastUpperBound(PsiType[] psiTypes) { + PsiType result = null; + final PsiManager manager = getPsiManager(); + for (final PsiType other : psiTypes) { + result = getLeastUpperBound(result, other, manager); + } + return result == null ? PsiType.getJavaLangObject(manager, getResolveScope()) : result; + } + + protected PsiManager getPsiManager() { + return PsiManager.getInstance(myFacade.getProject()); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java new file mode 100644 index 000000000000..195a1922e7d0 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java @@ -0,0 +1,145 @@ +/* + * Copyright 2000-2009 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.lang.psi.impl; + +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +/** + * @author peter + */ +public class GrMapType extends GrLiteralClassType { + private final Map myStringEntries; + private final List> myOtherEntries; + @NonNls + private static final String JAVA_UTIL_LINKED_HASH_MAP = "java.util.LinkedHashMap"; + private final String myJavaClassName; + + + public GrMapType(JavaPsiFacade facade, + GlobalSearchScope scope, + Map stringEntries, + List> otherEntries) { + this(facade, scope, stringEntries, otherEntries, LanguageLevel.JDK_1_5); + } + + + public GrMapType(JavaPsiFacade facade, + GlobalSearchScope scope, + Map stringEntries, + List> otherEntries, LanguageLevel languageLevel) { + super(languageLevel, scope, facade); + myStringEntries = stringEntries; + myOtherEntries = otherEntries; + + myJavaClassName = facade.findClass(JAVA_UTIL_LINKED_HASH_MAP, scope) != null ? JAVA_UTIL_LINKED_HASH_MAP : CommonClassNames.JAVA_UTIL_MAP; + } + + @Override + protected String getJavaClassName() { + return myJavaClassName; + } + + public String getClassName() { + return "Map"; + } + + public PsiType[] getAllKeyTypes() { + Set result = new HashSet(); + if (!myStringEntries.isEmpty()) { + result.add(PsiType.getJavaLangString(getPsiManager(), getResolveScope())); + } + for (Pair entry : myOtherEntries) { + result.add(entry.first); + } + result.remove(null); + return result.toArray(new PsiType[result.size()]); + } + + public PsiType[] getAllValueTypes() { + Set result = new HashSet(); + result.addAll(myStringEntries.values()); + for (Pair entry : myOtherEntries) { + result.add(entry.second); + } + result.remove(null); + return result.toArray(new PsiType[result.size()]); + } + + @NotNull + public PsiType[] getParameters() { + final PsiType[] keyTypes = getAllKeyTypes(); + final PsiType[] valueTypes = getAllValueTypes(); + if (keyTypes.length == 0 && valueTypes.length == 0) { + return PsiType.EMPTY_ARRAY; + } + + return new PsiType[]{getLeastUpperBound(keyTypes), getLeastUpperBound(valueTypes)}; + } + + public String getInternalCanonicalText() { + List components = new ArrayList(); + for (String s : myStringEntries.keySet()) { + components.add("'" + s + "':" + getInternalCanonicalText(myStringEntries.get(s))); + } + for (Pair entry : myOtherEntries) { + components.add(getInternalCanonicalText(entry.first) + ":" + getInternalCanonicalText(entry.second)); + } + return "[" + StringUtil.join(components, ", ") + "]"; + } + + public boolean isValid() { + for (PsiType type : myStringEntries.values()) { + if (type != null && !type.isValid()) { + return false; + } + } + for (Pair entry : myOtherEntries) { + if (entry.first != null && !entry.first.isValid()) { + return false; + } + if (entry.second != null && !entry.second.isValid()) { + return false; + } + } + + return true; + } + + public PsiClassType setLanguageLevel(final LanguageLevel languageLevel) { + return new GrMapType(myFacade, getResolveScope(), myStringEntries, myOtherEntries, languageLevel); + } + + public boolean equals(Object obj) { + if (obj instanceof GrMapType) { + return myStringEntries.equals(((GrMapType)obj).myStringEntries) && myOtherEntries.equals(((GrMapType)obj).myOtherEntries); + } + return super.equals(obj); + } + + public boolean isAssignableFrom(@NotNull PsiType type) { + return false; + } + +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java index ed0cfc6242b2..1ccfad5ba4da 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java @@ -20,35 +20,25 @@ import com.intellij.openapi.util.Comparing; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; /** * @author ven */ -public class GrTupleType extends PsiClassType { - private final GlobalSearchScope myScope; - private final JavaPsiFacade myFacade; +public class GrTupleType extends GrLiteralClassType { private final PsiType[] myComponentTypes; - @NonNls - private static final String JAVA_UTIL_LIST = "java.util.List"; - public GrTupleType(PsiType[] componentTypes, JavaPsiFacade facade, GlobalSearchScope scope) { this(componentTypes, facade, scope,LanguageLevel.JDK_1_5); } public GrTupleType(PsiType[] componentTypes, JavaPsiFacade facade, GlobalSearchScope scope,LanguageLevel languageLevel) { - super(languageLevel); + super(languageLevel, scope, facade); myComponentTypes = componentTypes; - myFacade = facade; - myScope = scope; } - @Nullable - public PsiClass resolve() { - return myFacade.findClass(JAVA_UTIL_LIST, getResolveScope()); + @Override + protected String getJavaClassName() { + return CommonClassNames.JAVA_UTIL_LIST; } public String getClassName() { @@ -58,73 +48,7 @@ public class GrTupleType extends PsiClassType { @NotNull public PsiType[] getParameters() { if (myComponentTypes.length == 0) return PsiType.EMPTY_ARRAY; - PsiType result = myComponentTypes[0]; - for (int i = 1; i < myComponentTypes.length; i++) { - final PsiType other = myComponentTypes[i]; - if (other == null) continue; - if (result == null) result = other; - if (result.isAssignableFrom(other)) continue; - if (other.isAssignableFrom(result)) result = other; - result = TypesUtil.getLeastUpperBound(result, other, PsiManager.getInstance(myFacade.getProject())); - } - - return new PsiType[]{result}; - } - - @NotNull - public ClassResolveResult resolveGenerics() { - return new ClassResolveResult() { - private final PsiClass myListClass = resolve(); - - public PsiClass getElement() { - return myListClass; - } - - public PsiSubstitutor getSubstitutor() { - PsiSubstitutor result = PsiSubstitutor.EMPTY; - PsiType[] typeArgs = getParameters(); - if (myListClass != null && myListClass.getTypeParameters().length == 1 && typeArgs.length == 1) { - result = result.put(myListClass.getTypeParameters()[0], typeArgs[0]); - } - return result; - } - - public boolean isPackagePrefixPackageReference() { - return false; - } - - public boolean isAccessible() { - return true; - } - - public boolean isStaticsScopeCorrect() { - return true; - } - - public PsiElement getCurrentFileResolveScope() { - return null; - } - - public boolean isValidResult() { - return isStaticsScopeCorrect() && isAccessible(); - } - }; - } - - @NotNull - public PsiClassType rawType() { - return myFacade.getElementFactory().createTypeByFQClassName(JAVA_UTIL_LIST, myScope); - } - - public String getPresentableText() { - return "List"; - } - - @Nullable - public String getCanonicalText() { - PsiClass resolved = resolve(); - if (resolved == null) return null; - return resolved.getQualifiedName(); + return new PsiType[]{getLeastUpperBound(myComponentTypes)}; } public String getInternalCanonicalText() { @@ -132,9 +56,7 @@ public class GrTupleType extends PsiClassType { builder.append("["); for (int i = 0; i < myComponentTypes.length; i++) { if (i > 0) builder.append(", "); - PsiType type = myComponentTypes[i]; - @NonNls String componentText = type == null ? "java.lang.Object" : type.getInternalCanonicalText(); - builder.append(componentText); + builder.append(getInternalCanonicalText(myComponentTypes[i])); } builder.append("]"); return builder.toString(); @@ -147,23 +69,8 @@ public class GrTupleType extends PsiClassType { return true; } - public boolean equalsToText(@NonNls String text) { - return text.equals(JAVA_UTIL_LIST); - } - - @NotNull - public GlobalSearchScope getResolveScope() { - return myScope; - } - - @NotNull - public LanguageLevel getLanguageLevel() { - return myLanguageLevel; - } - public PsiClassType setLanguageLevel(final LanguageLevel languageLevel) { - GrTupleType copy = new GrTupleType(myComponentTypes, myFacade, myScope,languageLevel); - return copy; + return new GrTupleType(myComponentTypes, myFacade, myScope,languageLevel); } public boolean equals(Object obj) { @@ -197,7 +104,4 @@ public class GrTupleType extends PsiClassType { return myComponentTypes; } - public GlobalSearchScope getScope() { - return myScope; - } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java index d68545e597aa..17b078dc96a0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java @@ -31,6 +31,7 @@ import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.NotNullFunction; import com.intellij.util.containers.ConcurrentWeakHashMap; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; @@ -103,35 +104,39 @@ public class GroovyPsiManager { @NotNull private Map> buildGDK() { final HashMap> newMap = new HashMap>(); - - PsiClass defaultMethodsClass = - JavaPsiFacade.getInstance(myProject).findClass(DEFAULT_METHODS_QNAME, GlobalSearchScope.allScope(myProject)); - if (defaultMethodsClass != null) { - for (PsiMethod method : defaultMethodsClass.getMethods()) { - if (method.isConstructor()) continue; - addDefaultMethod(method, newMap, false); + addCategoryMethods(DEFAULT_METHODS_QNAME, newMap, new NotNullFunction() { + @NotNull + public PsiMethod fun(PsiMethod method) { + return new GrGdkMethodImpl(method, false); } - - } - - PsiClass defaultStaticMethodsClass = - JavaPsiFacade.getInstance(myProject).findClass(DEFAULT_STATIC_METHODS_QNAME, GlobalSearchScope.allScope(myProject)); - if (defaultStaticMethodsClass != null) { - for (PsiMethod method : defaultStaticMethodsClass.getMethods()) { - if (method.isConstructor()) continue; - addDefaultMethod(method, newMap, true); + }); + addCategoryMethods(DEFAULT_STATIC_METHODS_QNAME, newMap, new NotNullFunction() { + @NotNull + public PsiMethod fun(PsiMethod method) { + return new GrGdkMethodImpl(method, true); } - } + }); addSwingBuilderMethods(newMap); return newMap; } - private static void addDefaultMethod(PsiMethod method, HashMap> map, boolean isStatic) { + public void addCategoryMethods(String fromClass, Map> toMap, NotNullFunction converter) { + PsiClass categoryClass = JavaPsiFacade.getInstance(myProject).findClass(fromClass, GlobalSearchScope.allScope(myProject)); + if (categoryClass != null) { + for (PsiMethod method : categoryClass.getMethods()) { + if (method.isConstructor()) continue; + if (!method.hasModifierProperty(PsiModifier.STATIC) || !method.hasModifierProperty(PsiModifier.PUBLIC)) continue; + addDefaultMethod(method, toMap, converter); + } + } + } + + private static void addDefaultMethod(PsiMethod method, Map> map, NotNullFunction converter) { if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return; PsiParameter[] parameters = method.getParameterList().getParameters(); - LOG.assertTrue(parameters.length > 0); + LOG.assertTrue(parameters.length > 0, method.getName()); PsiType thisType = TypeConversionUtil.erasure(parameters[0].getType()); String thisCanonicalText = thisType.getCanonicalText(); LOG.assertTrue(thisCanonicalText != null); @@ -140,7 +145,7 @@ public class GroovyPsiManager { hisMethods = new ArrayList(); map.put(thisCanonicalText, hisMethods); } - hisMethods.add(new GrGdkMethodImpl(method, isStatic)); + hisMethods.add(converter.fun(method)); } private static final String[] SWING_WIDGETS_METHODS = diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java index 043c71b375e6..c80df51fcce9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java @@ -15,10 +15,12 @@ */ package org.jetbrains.plugins.groovy.lang.psi.impl; +import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNamedElement; import com.intellij.psi.PsiSubstitutor; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; @@ -43,7 +45,7 @@ public class GroovyResolveResultImpl implements GroovyResolveResult { boolean isAccessible, boolean staticsOK) { myCurrentFileResolveContext = context; - myElement = element; + myElement = element instanceof PsiClass? GrClassSubstitutor.getSubstitutedClass((PsiClass)element) : element; myIsAccessible = isAccessible; mySubstitutor = substitutor; myIsStaticsOK = staticsOK; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java index 969465c6aab1..e1e3d6d9d631 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java @@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary; import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.TokenSet; @@ -31,14 +32,16 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaratio import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrParenthesizedExpression; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrExpressionImpl; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import java.util.ArrayList; +import java.util.HashMap; + import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mCOMMA; /** @@ -111,69 +114,27 @@ public class GrListOrMapImpl extends GrExpressionImpl implements GrListOrMap { @Nullable private static PsiClassType inferMapInitializerType(GrListOrMapImpl listOrMap, JavaPsiFacade facade, GlobalSearchScope scope) { - PsiClass mapClass = facade.findClass("java.util.LinkedHashMap", scope); - if (mapClass == null) { - mapClass = facade.findClass(CommonClassNames.JAVA_UTIL_MAP, scope); - } - PsiElementFactory factory = facade.getElementFactory(); - if (mapClass != null) { - PsiTypeParameter[] typeParameters = mapClass.getTypeParameters(); - if (typeParameters.length == 2) { - GrNamedArgument[] namedArgs = listOrMap.getNamedArguments(); - GrExpression[] values = new GrExpression[namedArgs.length]; - GrArgumentLabel[] labels = new GrArgumentLabel[namedArgs.length]; - - for (int i = 0; i < values.length; i++) { - GrExpression expr = namedArgs[i].getExpression(); - if (expr == null) return null; - values[i] = expr; - GrArgumentLabel label = namedArgs[i].getLabel(); - if (label == null) return null; - labels[i] = label; - } - - PsiType initializerType = getInitializerType(values); - PsiType labelType = getLabelsType(labels); - PsiSubstitutor substitutor = PsiSubstitutor.EMPTY. - put(typeParameters[0], labelType). - put(typeParameters[1], initializerType); - return factory.createType(mapClass, substitutor); + final HashMap stringEntries = new HashMap(); + final ArrayList> otherEntries = new ArrayList>(); + GrNamedArgument[] namedArgs = listOrMap.getNamedArguments(); + for (GrNamedArgument namedArg : namedArgs) { + final GrArgumentLabel label = namedArg.getLabel(); + final GrExpression expression = namedArg.getExpression(); + if (label == null || expression == null) { + continue; } - else { - return facade.getElementFactory().createType(mapClass); + + final String name = label.getName(); + if (name != null) { + stringEntries.put(name, expression.getType()); + } else { + otherEntries.add(Pair.create(label.getLabelType(), expression.getType())); } } - return null; + + return new GrMapType(facade, scope, stringEntries, otherEntries); } - @Nullable - private static PsiType getLabelsType(GrArgumentLabel[] labels) { - if (labels.length == 0) return null; - PsiType result = null; - PsiManager manager = labels[0].getManager(); - final PsiElementFactory factory = JavaPsiFacade.getElementFactory(labels[0].getProject()); - for (GrArgumentLabel label : labels) { - PsiElement el = label.getNameElement(); - PsiType other; - if (el instanceof GrParenthesizedExpression) { - other = ((GrParenthesizedExpression)el).getType(); - } - else { - final ASTNode node = el.getNode(); - if (node != null) { - other = TypesUtil.getPsiType(el, node.getElementType()); - if (other == null) { - other = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, el.getResolveScope()); - } - } - else { - other = null; - } - } - result = getLeastUpperBound(result, other, manager); - } - return result; - } private static PsiClassType getTupleType(GrExpression[] initializers, GrListOrMap listOrMap) { PsiType[] result = new PsiType[initializers.length]; @@ -184,28 +145,5 @@ public class GrListOrMapImpl extends GrExpressionImpl implements GrListOrMap { return new GrTupleType(result, JavaPsiFacade.getInstance(listOrMap.getProject()), listOrMap.getResolveScope()); } - @Nullable - private static PsiType getInitializerType(GrExpression[] initializers) { - if (initializers.length == 0) return null; - PsiManager manager = initializers[0].getManager(); - PsiType result = initializers[0].getType(); - for (int i = 1; i < initializers.length; i++) { - result = getLeastUpperBound(result, initializers[i].getType(), manager); - } - - return result; - } - - @Nullable - private static PsiType getLeastUpperBound(PsiType result, PsiType other, PsiManager manager) { - if (other == null) return result; - if (result == null) result = other; - if (result.isAssignableFrom(other)) return result; - if (other.isAssignableFrom(result)) result = other; - - result = TypesUtil.getLeastUpperBound(result, other, manager); - return result; - } - } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java index a9e3286f4cf8..f1706a99b5b1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java @@ -22,11 +22,13 @@ import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference; import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PropertyUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; @@ -34,9 +36,12 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgument import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrParenthesizedExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiElementImpl; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -68,12 +73,29 @@ public class GrArgumentLabelImpl extends GroovyPsiElementImpl implements GrArgum @Nullable public String getName() { final PsiElement element = getNameElement(); - if (element instanceof GrExpression) { - return null; + if (element instanceof GrLiteral) { + final Object value = ((GrLiteral)element).getValue(); + if (value instanceof String) { + return (String) value; + } } - else { + if (element instanceof GrExpression) { + final Object value = JavaPsiFacade.getInstance(getProject()).getConstantEvaluationHelper().computeConstantExpression(element); + if (value instanceof String) { + return (String)value; + } + } + + final IElementType elemType = element.getNode().getElementType(); + if (GroovyTokenTypes.mIDENT == elemType) { + return element.getText(); + } + + if (CommonClassNames.JAVA_LANG_STRING.equals(TypesUtil.getPsiTypeName(elemType))) { return GrStringUtil.removeQuotes(element.getText()); } + + return null; } public PsiElement getElement() { @@ -215,6 +237,24 @@ public class GrArgumentLabelImpl extends GroovyPsiElementImpl implements GrArgum return null; } + public PsiType getLabelType() { + PsiElement el = getNameElement(); + if (el instanceof GrParenthesizedExpression) { + return ((GrParenthesizedExpression)el).getType(); + } + + final ASTNode node = el.getNode(); + if (node == null) { + return null; + } + + PsiType nodeType = TypesUtil.getPsiType(el, node.getElementType()); + if (nodeType != null) { + return nodeType; + } + return PsiType.getJavaLangString(PsiManager.getInstance(el.getProject()), el.getResolveScope()); + } + public GrNamedArgument getNamedArgument() { final PsiElement parent = getParent(); assert parent instanceof GrNamedArgument; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java index 0c5341c8f42e..eebd50375f53 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java @@ -23,7 +23,6 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; @@ -39,11 +38,8 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path.GrCallExpressionImpl; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; -import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersProcessor; -import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** @@ -135,7 +131,7 @@ public class GrNewExpressionImpl extends GrCallExpressionImpl implements GrNewEx if (classResults.length == 0) return GroovyResolveResult.EMPTY_ARRAY; if (getNamedArguments().length > 0 && getArgumentList().getExpressionArguments().length == 0) { - GroovyResolveResult[] constructorResults = getCandidates(ref, classResults, new PsiType[]{PsiUtil.createMapType(getManager(), getResolveScope())}); //one Map parameter, actually + GroovyResolveResult[] constructorResults = PsiUtil.getConstructorCandidates(ref, classResults, new PsiType[]{PsiUtil.createMapType(getManager(), getResolveScope())}); //one Map parameter, actually for (GroovyResolveResult result : constructorResults) { if (result.getElement() instanceof PsiMethod) { PsiMethod constructor = (PsiMethod)result.getElement(); @@ -145,46 +141,19 @@ public class GrNewExpressionImpl extends GrCallExpressionImpl implements GrNewEx } } } - final GroovyResolveResult[] emptyConstructors = getCandidates(ref, classResults, PsiType.EMPTY_ARRAY); + final GroovyResolveResult[] emptyConstructors = PsiUtil.getConstructorCandidates(ref, classResults, PsiType.EMPTY_ARRAY); if (emptyConstructors.length > 0) { return emptyConstructors; } } - return getCandidates(ref, classResults, PsiUtil.getArgumentTypes(ref, false)); + return PsiUtil.getConstructorCandidates(ref, classResults, PsiUtil.getArgumentTypes(ref, false)); } public GroovyResolveResult[] multiResolveClass() { return getReferenceElement().multiResolve(false); } - private GroovyResolveResult[] getCandidates(GrCodeReferenceElement ref, GroovyResolveResult[] classResults, PsiType[] argTypes) { - List constructorResults = new ArrayList(); - for (GroovyResolveResult classResult : classResults) { - final PsiElement element = classResult.getElement(); - if (element instanceof PsiClass) { - final GroovyPsiElement context = classResult.getCurrentFileResolveContext(); - PsiClass clazz = (PsiClass)element; - String className = clazz.getName(); - PsiType thisType = JavaPsiFacade.getInstance(getProject()).getElementFactory().createType(clazz, classResult.getSubstitutor()); - final MethodResolverProcessor processor = new MethodResolverProcessor(className, ref, true, thisType, argTypes, PsiType.EMPTY_ARRAY) - ; - processor.setCurrentFileResolveContext(context); - PsiSubstitutor substitutor = classResult.getSubstitutor(); - final boolean toBreak = - element.processDeclarations(processor, ResolveState.initial().put(PsiSubstitutor.KEY, substitutor), null, ref); - - for (NonCodeMembersProcessor membersProcessor : NonCodeMembersProcessor.EP_NAME.getExtensions()) { - if (!membersProcessor.processNonCodeMembers(thisType, processor, this, true)) break; - } - constructorResults.addAll(Arrays.asList(processor.getCandidates())); - if (!toBreak) break; - } - } - - return constructorResults.toArray(new GroovyResolveResult[constructorResults.size()]); - } - public PsiMethod resolveConstructor() { return PsiImplUtil.extractUniqueElement(multiResolveConstructor()); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java index 39caf4a869fe..db0774ab8b5b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java @@ -217,9 +217,27 @@ public class TypesUtil { } public static boolean isAssignable(PsiType lType, PsiType rType, PsiManager manager, GlobalSearchScope scope) { - if (isAssignableByMethodCallConversion(lType, rType, manager, scope)){ + return isAssignable(lType, rType, manager, scope, true); + } + + public static boolean isAssignable(PsiType lType, PsiType rType, PsiManager manager, GlobalSearchScope scope, boolean allowConversion) { + if (allowConversion && isAssignableByMethodCallConversion(lType, rType, manager, scope)) { return true; } + + return _isAssignable(lType, rType, manager, scope); + } + + public static boolean isAssignable(PsiType lType, PsiType rType, GroovyPsiElement context) { + return isAssignableByMethodCallConversion(lType, rType, context) || + _isAssignable(lType, rType, context.getManager(), context.getResolveScope()); + } + + private static boolean _isAssignable(PsiType lType, PsiType rType, PsiManager manager, GlobalSearchScope scope) { + if (lType == null || rType == null) { + return false; + } + //all numeric types are assignable if (isNumericType(lType)) { return isNumericType(rType) || rType.equals(PsiType.NULL); @@ -234,16 +252,22 @@ public class TypesUtil { return lType.isAssignableFrom(rType); } - public static boolean isAssignableByMethodCallConversion(PsiType lType, PsiType rType, PsiManager manager, GlobalSearchScope scope) { + public static boolean isAssignableByMethodCallConversion(PsiType lType, PsiType rType, GroovyPsiElement context) { if (lType == null || rType == null) return false; for (GrTypeConverter converter : GrTypeConverter.EP_NAME.getExtensions()) { - final Boolean result = converter.isConvertible(lType, rType, manager, scope); + final Boolean result = converter.isConvertible(lType, rType, context); if (result != null) { return result; } } + return isAssignableByMethodCallConversion(lType, rType, context.getManager(), context.getResolveScope()); + } + + public static boolean isAssignableByMethodCallConversion(PsiType lType, PsiType rType, PsiManager manager, GlobalSearchScope scope) { + if (lType == null || rType == null) return false; + if (rType instanceof GrTupleType) { final GrTupleType tuple = (GrTupleType)rType; if (tuple.getComponentTypes().length == 0) { @@ -402,7 +426,7 @@ public class TypesUtil { } @Nullable - private static String getPsiTypeName(IElementType elemType) { + public static String getPsiTypeName(IElementType elemType) { return ourPrimitiveTypesToClassNames.get(elemType); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/params/GrParameterImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/params/GrParameterImpl.java index cbf21f4789b7..cb47e248809a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/params/GrParameterImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/params/GrParameterImpl.java @@ -201,12 +201,4 @@ public class GrParameterImpl extends GrVariableImpl implements GrParameter { return PsiAnnotation.EMPTY_ARRAY; } - @Override - public PsiType getDeclaredType() { - PsiType type = super.getDeclaredType(); - if (type == null) { - type = getTypeGroovy(); - } - return type; - } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/ClosureSyntheticParameter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/ClosureSyntheticParameter.java index c63422dab1d6..9a4200f43867 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/ClosureSyntheticParameter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/ClosureSyntheticParameter.java @@ -29,6 +29,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableBase; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; /** * @author ven @@ -53,7 +54,11 @@ public class ClosureSyntheticParameter extends LightParameter implements Navigat @Nullable public PsiType getTypeGroovy() { - return GrVariableEnhancer.getEnhancedType(this); + PsiType typeGroovy = GrVariableEnhancer.getEnhancedType(this); + if (typeGroovy instanceof PsiIntersectionType) { + return ((PsiIntersectionType)typeGroovy).getRepresentative(); + } + return typeGroovy; } @Nullable @@ -83,11 +88,7 @@ public class ClosureSyntheticParameter extends LightParameter implements Navigat @NotNull @Override public PsiType getType() { - PsiType typeGroovy = getTypeGroovy(); - if (typeGroovy instanceof PsiIntersectionType) { - typeGroovy=((PsiIntersectionType)typeGroovy).getRepresentative(); - } - return typeGroovy != null ? typeGroovy : super.getType(); + return TypesUtil.getJavaLangObject(this); } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureParameterImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureParameterImpl.java index 39ee2d7315cf..15bcdd1daab8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureParameterImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureParameterImpl.java @@ -35,16 +35,7 @@ public class GrClosureParameterImpl implements GrClosureParameter { public GrClosureParameterImpl(PsiType type, boolean optional, GrExpression defaultInitializer) { myType = type; myOptional = optional; - if (myOptional) { - myDefaultInitializer = defaultInitializer; - } - else { - myDefaultInitializer = null; - } - } - - public GrClosureParameterImpl(PsiParameter parameter) { - this(parameter, PsiSubstitutor.EMPTY); + myDefaultInitializer = optional ? defaultInitializer : null; } public GrClosureParameterImpl(PsiParameter parameter, PsiSubstitutor substitutor) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java index 7582e9798de4..eb6147bad105 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java @@ -24,6 +24,7 @@ import com.intellij.psi.util.MethodSignatureUtil; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; @@ -46,10 +47,6 @@ public class GrClosureSignatureUtil { private GrClosureSignatureUtil() { } - public static GrClosureSignature createSignature(PsiMethod method) { - return new GrClosureSignatureImpl(method); - } - public static GrClosureSignature createSignature(GrClosableBlock block) { return new GrClosureSignatureImpl(block); } @@ -62,20 +59,20 @@ public class GrClosureSignatureUtil { return new GrClosureSignatureImpl(parameters, returnType); } - public static boolean isSignatureApplicable(GrClosureSignature signature, PsiType[] args, PsiManager manager, GlobalSearchScope scope) { - if (isApplicable(signature, args, manager, scope)) return true; + public static boolean isSignatureApplicable(GrClosureSignature signature, PsiType[] args, GroovyPsiElement context) { + if (isApplicable(signature, args, context)) return true; if (args.length == 1) { PsiType arg = args[0]; if (arg instanceof GrTupleType) { args = ((GrTupleType)arg).getComponentTypes(); - if (isApplicable(signature, args, manager, scope)) return true; + if (isApplicable(signature, args, context)) return true; } } return false; } - private static boolean isApplicable(GrClosureSignature signature, PsiType[] args, PsiManager manager, GlobalSearchScope scope) { + private static boolean isApplicable(GrClosureSignature signature, PsiType[] args, GroovyPsiElement context) { GrClosureParameter[] params = signature.getParameters(); if (args.length > params.length && !signature.isVarargs()) return false; int optional = getOptionalParamCount(signature, false); @@ -83,11 +80,11 @@ public class GrClosureSignatureUtil { if (signature.isVarargs()) notOptional--; if (notOptional > args.length) return false; - if (isApplicable(params, args, params.length, args.length, manager, scope)) { + if (isApplicable(params, args, params.length, args.length, context)) { return true; } if (signature.isVarargs()) { - return new ApplicabilityVerifierForVararg(manager, scope, params, args).isApplicable(); + return new ApplicabilityVerifierForVararg(context, params, args).isApplicable(); } return false; } @@ -96,8 +93,7 @@ public class GrClosureSignatureUtil { PsiType[] args, int paramCount, int argCount, - PsiManager manager, - GlobalSearchScope scope) { + GroovyPsiElement context) { int optional = getOptionalParamCount(params, false); int notOptional = paramCount - optional; int optionalArgs = argCount - notOptional; @@ -108,22 +104,20 @@ public class GrClosureSignatureUtil { } if (cur == paramCount) return false; if (params[cur].isOptional()) optionalArgs--; - if (!TypesUtil.isAssignableByMethodCallConversion(params[cur].getType(), args[i], manager, scope)) return false; + if (!TypesUtil.isAssignableByMethodCallConversion(params[cur].getType(), args[i], context)) return false; } return true; } private static class ApplicabilityVerifierForVararg { - private PsiManager manager; - GlobalSearchScope scope; + private GroovyPsiElement context; GrClosureParameter[] params; PsiType[] args; PsiType vararg; private int paramLength; - private ApplicabilityVerifierForVararg(PsiManager manager, GlobalSearchScope scope, GrClosureParameter[] params, PsiType[] args) { - this.manager = manager; - this.scope = scope; + private ApplicabilityVerifierForVararg(GroovyPsiElement context, GrClosureParameter[] params, PsiType[] args) { + this.context = context; this.params = params; this.args = args; paramLength = params.length - 1; @@ -150,14 +144,14 @@ public class GrClosureSignatureUtil { if (curParam == paramLength) break; if (params[curParam].isOptional()) { - if (TypesUtil.isAssignable(params[curParam].getType(), args[curArg], manager, scope) && + if (TypesUtil.isAssignable(params[curParam].getType(), args[curArg], context) && isApplicableInternal(curParam + 1, curArg + 1, false, notOptional)) { return true; } skipOptionals = true; } else { - if (!TypesUtil.isAssignableByMethodCallConversion(params[curParam].getType(), args[curArg], manager, scope)) return false; + if (!TypesUtil.isAssignableByMethodCallConversion(params[curParam].getType(), args[curArg], context)) return false; notOptional--; curArg++; curParam++; @@ -165,7 +159,7 @@ public class GrClosureSignatureUtil { } for (; curArg < args.length; curArg++) { - if (!TypesUtil.isAssignableByMethodCallConversion(vararg, args[curArg], manager, scope)) return false; + if (!TypesUtil.isAssignableByMethodCallConversion(vararg, args[curArg], context)) return false; } return true; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java index f6682466931d..a23fc8e951dc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java @@ -333,30 +333,6 @@ public class GrClassImplUtil { return isPlaceGroovy || !(method instanceof GrGdkMethod); } - private static boolean isPropertyReference(PsiElement place, PsiField aField, boolean isGetter) { - //filter only in groovy, todo: analyze java place - if (place.getLanguage() != GroovyFileType.GROOVY_FILE_TYPE.getLanguage()) return true; - - if (place instanceof GrReferenceExpression) { - final PsiElement parent = place.getParent(); - if (parent instanceof GrMethodCallExpression) { - final GrMethodCallExpression call = (GrMethodCallExpression)parent; - if (call.getNamedArguments().length > 0 || call.getClosureArguments().length > 0) return false; - final GrExpression[] args = call.getExpressionArguments(); - if (isGetter) { - return args.length == 0; - } - else { - return args.length == 1 && - TypesUtil - .isAssignableByMethodCallConversion(aField.getType(), args[0].getType(), place.getManager(), place.getResolveScope()); - } - } - } - - return false; - } - @Nullable public static PsiMethod findMethodBySignature(GrTypeDefinition grType, PsiMethod patternMethod, boolean checkBases) { final MethodSignature patternSignature = patternMethod.getSignature(PsiSubstitutor.EMPTY); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index a4f0001101d4..e3cf85bfad1b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -69,6 +69,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.JavaIdentifier; import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil; +import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersProcessor; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor; @@ -119,7 +120,7 @@ public class PsiUtil { public static boolean isApplicable(@Nullable PsiType[] argumentTypes, PsiMethod method, PsiSubstitutor substitutor, - boolean isInUseCategory) { + boolean isInUseCategory, GroovyPsiElement place) { if (argumentTypes == null) return true; GrClosureSignature signature = GrClosureSignatureUtil.createSignature(method, substitutor); @@ -132,14 +133,14 @@ public class PsiUtil { return InheritanceUtil.isInheritor(argumentTypes[0], CommonClassNames.JAVA_UTIL_MAP); } LOG.assertTrue(signature != null); - return GrClosureSignatureUtil.isSignatureApplicable(signature, argumentTypes, method.getManager(), method.getResolveScope()); + return GrClosureSignatureUtil.isSignatureApplicable(signature, argumentTypes, place); } - public static boolean isApplicable(@Nullable PsiType[] argumentTypes, GrClosureType type, PsiManager manager) { + public static boolean isApplicable(@Nullable PsiType[] argumentTypes, GrClosureType type, GroovyPsiElement context) { if (argumentTypes == null) return true; GrClosureSignature signature = type.getSignature(); - return GrClosureSignatureUtil.isSignatureApplicable(signature, argumentTypes, manager, type.getResolveScope()); + return GrClosureSignatureUtil.isSignatureApplicable(signature, argumentTypes, context); } public static PsiClassType createMapType(PsiManager manager, GlobalSearchScope scope) { @@ -763,4 +764,31 @@ public class PsiUtil { } return false; } + + public static GroovyResolveResult[] getConstructorCandidates(GroovyPsiElement place, GroovyResolveResult[] classCandidates, PsiType[] argTypes) { + List constructorResults = new ArrayList(); + for (GroovyResolveResult classResult : classCandidates) { + final PsiElement element = classResult.getElement(); + if (element instanceof PsiClass) { + final GroovyPsiElement context = classResult.getCurrentFileResolveContext(); + PsiClass clazz = (PsiClass)element; + String className = clazz.getName(); + PsiType thisType = JavaPsiFacade.getInstance(place.getProject()).getElementFactory().createType(clazz, classResult.getSubstitutor()); + final MethodResolverProcessor processor = new MethodResolverProcessor(className, place, true, thisType, argTypes, PsiType.EMPTY_ARRAY) + ; + processor.setCurrentFileResolveContext(context); + PsiSubstitutor substitutor = classResult.getSubstitutor(); + final boolean toBreak = + element.processDeclarations(processor, ResolveState.initial().put(PsiSubstitutor.KEY, substitutor), null, place); + + for (NonCodeMembersProcessor membersProcessor : NonCodeMembersProcessor.EP_NAME.getExtensions()) { + if (!membersProcessor.processNonCodeMembers(thisType, processor, place, true)) break; + } + constructorResults.addAll(Arrays.asList(processor.getCandidates())); + if (!toBreak) break; + } + } + + return constructorResults.toArray(new GroovyResolveResult[constructorResults.size()]); + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/DominanceAwareMethod.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/DominanceAwareMethod.java new file mode 100644 index 000000000000..e74f045fba59 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/DominanceAwareMethod.java @@ -0,0 +1,17 @@ +package org.jetbrains.plugins.groovy.lang.resolve; + +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; + +/** + * @author peter + */ +public interface DominanceAwareMethod extends PsiMethod { + + boolean dominates(@NotNull PsiSubstitutor substitutor, + @NotNull PsiMethod another, @NotNull PsiSubstitutor anotherSubstitutor, + @NotNull GroovyPsiElement context); + +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java index 33170c593d10..f8b3b7cb714a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java @@ -37,13 +37,17 @@ import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassResolverProcessor; import org.jetbrains.plugins.groovy.lang.resolve.processors.PropertyResolverProcessor; import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor; @@ -419,4 +423,42 @@ public class ResolveUtil { return true; } + + public static GroovyResolveResult[] getMethodVariants(GroovyPsiElement place) { + final PsiElement parent = place.getParent(); + GroovyResolveResult[] variants = GroovyResolveResult.EMPTY_ARRAY; + if (parent instanceof GrCallExpression) { + variants = ((GrCallExpression) parent).getMethodVariants(); + } else if (parent instanceof GrConstructorInvocation) { + final PsiClass clazz = ((GrConstructorInvocation) parent).getDelegatedClass(); + if (clazz != null) { + final PsiMethod[] constructors = clazz.getConstructors(); + variants = getConstructorResolveResult(constructors, place); + } + } else if (parent instanceof GrAnonymousClassDefinition) { + final PsiElement element = ((GrAnonymousClassDefinition)parent).getBaseClassReferenceGroovy().resolve(); + if (element instanceof PsiClass) { + final PsiMethod[] constructors = ((PsiClass)element).getConstructors(); + variants = getConstructorResolveResult(constructors, place); + } + } + else if (parent instanceof GrApplicationStatement) { + final GrExpression funExpr = ((GrApplicationStatement) parent).getFunExpression(); + if (funExpr instanceof GrReferenceExpression) { + variants = ((GrReferenceExpression) funExpr).getSameNameVariants(); + } + } else if (place instanceof GrReferenceExpression) { + variants = ((GrReferenceExpression) place).getSameNameVariants(); + } + return variants; + } + + public static GroovyResolveResult[] getConstructorResolveResult(PsiMethod[] constructors, PsiElement place) { + GroovyResolveResult[] variants = new GroovyResolveResult[constructors.length]; + for (int i = 0; i < constructors.length; i++) { + final boolean isAccessible = com.intellij.psi.util.PsiUtil.isAccessible(constructors[i], place, null); + variants[i] = new GroovyResolveResultImpl(constructors[i], isAccessible); + } + return variants; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java index c4f7d2641527..2f75a79a6f8e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java @@ -35,6 +35,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMe import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import org.jetbrains.plugins.groovy.lang.resolve.DominanceAwareMethod; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import java.util.*; @@ -75,7 +76,7 @@ public class MethodResolverProcessor extends ResolverProcessor { substitutor = obtainSubstitutor(substitutor, method); boolean isAccessible = isAccessible(method); boolean isStaticsOK = isStaticsOK(method); - if (PsiUtil.isApplicable(myArgumentTypes, method, substitutor, myCurrentFileResolveContext instanceof GrMethodCallExpression)) { + if (PsiUtil.isApplicable(myArgumentTypes, method, substitutor, myCurrentFileResolveContext instanceof GrMethodCallExpression, (GroovyPsiElement)myPlace)) { myCandidates.add(new GroovyResolveResultImpl(method, myCurrentFileResolveContext, substitutor, isAccessible, isStaticsOK)); } else { myInapplicableCandidates.add(new GroovyResolveResultImpl(method, myCurrentFileResolveContext, substitutor, isAccessible, isStaticsOK)); @@ -241,6 +242,10 @@ public class MethodResolverProcessor extends ResolverProcessor { private boolean dominated(PsiMethod method1, PsiSubstitutor substitutor1, PsiMethod method2, PsiSubstitutor substitutor2, PsiManager manager, GlobalSearchScope scope) { //method1 has more general parameter types thn method2 if (!method1.getName().equals(method2.getName())) return false; + if (method1 instanceof DominanceAwareMethod && ((DominanceAwareMethod)method1).dominates(substitutor1, method2, substitutor2, (GroovyPsiElement)myPlace)) { + return true; + } + //hack for default gdk methods if (method1 instanceof GrGdkMethod && method2 instanceof GrGdkMethod) { method1 = ((GrGdkMethod)method1).getStaticMethod(); @@ -264,6 +269,18 @@ public class MethodResolverProcessor extends ResolverProcessor { for (int i = 0; i < params2.length; i++) { PsiType type1 = substitutor1.substitute(params1[i].getType()); PsiType type2 = substitutor2.substitute(params2[i].getType()); + + if (myArgumentTypes != null && myArgumentTypes.length > i) { + PsiType argType = myArgumentTypes[i]; + if (argType != null) { + final boolean converts1 = TypesUtil.isAssignable(type1, argType, manager, scope, false); + final boolean converts2 = TypesUtil.isAssignable(type2, argType, manager, scope, false); + if (converts1 != converts2) { + return converts2; + } + } + } + if (!typesAgree(manager, scope, type1, type2)) return false; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/stubs/GroovyCacheUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/stubs/GroovyCacheUtil.java index 617399f50486..90484d43d8a9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/stubs/GroovyCacheUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/stubs/GroovyCacheUtil.java @@ -21,6 +21,7 @@ import com.intellij.psi.PsiMember; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.stubs.StubIndex; import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; @@ -46,15 +47,15 @@ public abstract class GroovyCacheUtil { } @NotNull - public static GrTypeDefinition[] getDeriverCandidates(PsiClass clazz, GlobalSearchScope scope) { + public static PsiClass[] getDeriverCandidates(PsiClass clazz, GlobalSearchScope scope) { final String name = clazz.getName(); if (name == null) return GrTypeDefinition.EMPTY_ARRAY; - final ArrayList inheritors = new ArrayList(); + final ArrayList inheritors = new ArrayList(); final Collection refLists = StubIndex.getInstance().get(GrDirectInheritorsIndex.KEY, name, clazz.getProject(), scope); for (GrReferenceList list : refLists) { final PsiElement parent = list.getParent(); if (parent instanceof GrTypeDefinition) { - inheritors.add(((GrTypeDefinition)parent)); + inheritors.add(GrClassSubstitutor.getSubstitutedClass(((GrTypeDefinition)parent))); } } final Collection classes = @@ -62,7 +63,7 @@ public abstract class GroovyCacheUtil { for (GrAnonymousClassDefinition aClass : classes) { inheritors.add(aClass); } - return inheritors.toArray(new GrTypeDefinition[inheritors.size()]); + return inheritors.toArray(new PsiClass[inheritors.size()]); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java index 01e28b64a4b3..57f65851f298 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java @@ -78,7 +78,7 @@ public class GroovyOverrideImplementUtil { if (isImplement && aClass.isInterface()) return; - Collection candidates = OverrideImplementUtil.getMethodsToOverrideImplement(aClass, isImplement); + Collection candidates = getMethodsToOverrideImplement(aClass, isImplement); if (candidates.isEmpty()) return; List classMembers = new ArrayList(); @@ -178,6 +178,10 @@ public class GroovyOverrideImplementUtil { } } + public static Collection getMethodsToOverrideImplement(GrTypeDefinition aClass, boolean isImplement) { + return OverrideImplementUtil.getMethodsToOverrideImplement(aClass, isImplement); + } + private static void positionCaret(Editor editor, GrMethod result) { final GrOpenBlock body = result.getBlock(); if (body == null) return; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyMethodInliner.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyMethodInliner.java index 6b14a975f408..4b73e716dfe0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyMethodInliner.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyMethodInliner.java @@ -21,8 +21,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; -import com.intellij.openapi.editor.ex.DocumentEx; -import com.intellij.openapi.editor.impl.PersistentRangeMarker; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; @@ -58,7 +56,10 @@ import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; import org.jetbrains.plugins.groovy.refactoring.NameValidator; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; /** * @author ilyas @@ -85,10 +86,10 @@ public class GroovyMethodInliner implements InlineHandler.Inliner { Map conflicts = new HashMap(); for (GroovyInlineMethodUtil.ReferenceExpressionInfo info : infos) { - if (!(PsiUtil.isAccessible(call, info.declaration))) { + if (!PsiUtil.isAccessible(call, info.declaration)) { if (info.declaration instanceof PsiMethod) { String className = info.containingClass.getName(); - String signature = GroovyRefactoringUtil.getMethodSignature(((PsiMethod) info.declaration)); + String signature = GroovyRefactoringUtil.getMethodSignature((PsiMethod) info.declaration); String name = CommonRefactoringUtil.htmlEmphasize(className + "." + signature); conflicts.put(info.declaration, GroovyRefactoringBundle.message("method.is.not.accessible.form.context.0", name)); } else if (info.declaration instanceof PsiField) { @@ -147,9 +148,9 @@ public class GroovyMethodInliner implements InlineHandler.Inliner { qualifier = ((GrParenthesizedExpression) qualifier).getOperand(); } qualifierDeclaration = factory.createVariableDeclaration(ArrayUtil.EMPTY_STRING_ARRAY, qualifier, null, qualName); - innerQualifier = ((GrReferenceExpression) factory.createExpressionFromText(qualName)); + innerQualifier = (GrReferenceExpression) factory.createExpressionFromText(qualName); } else { - innerQualifier = ((GrReferenceExpression) qualifier); + innerQualifier = (GrReferenceExpression) qualifier; } } } @@ -159,7 +160,7 @@ public class GroovyMethodInliner implements InlineHandler.Inliner { if (result != null) { GrExpression expression = call.replaceWithExpression(result, false); TextRange range = expression.getTextRange(); - return editor != null ? new PersistentRangeMarker((DocumentEx)editor.getDocument(), range.getStartOffset(), range.getEndOffset()) : null; + return editor != null ? editor.getDocument().createRangeMarker(range.getStartOffset(), range.getEndOffset(), true) : null; } String resultName = InlineMethodConflictSolver.suggestNewName("result", newMethod, call); @@ -245,13 +246,13 @@ public class GroovyMethodInliner implements InlineHandler.Inliner { assert replaced != null; TextRange range = replaced.getTextRange(); - RangeMarker marker = editor != null ? new PersistentRangeMarker((DocumentEx)editor.getDocument(), range.getStartOffset(), range.getEndOffset()) : null; + RangeMarker marker = editor != null ? editor.getDocument().createRangeMarker(range.getStartOffset(), range.getEndOffset(), true) : null; reformatOwner(owner); return marker; } else { GrStatement stmt; if (isTailMethodCall && enclosingExpr.getParent() instanceof GrReturnStatement) { - stmt = ((GrReturnStatement) enclosingExpr.getParent()); + stmt = (GrReturnStatement) enclosingExpr.getParent(); } else { stmt = enclosingExpr; } @@ -332,7 +333,7 @@ public class GroovyMethodInliner implements InlineHandler.Inliner { if (statement instanceof GrReturnStatement) { expr = ((GrReturnStatement) statement).getReturnValue(); } else { - expr = ((GrExpression) statement); + expr = (GrExpression) statement; } return expr; } @@ -382,7 +383,7 @@ public class GroovyMethodInliner implements InlineHandler.Inliner { if (element == null) return; for (PsiElement child : element.getChildren()) { if (child instanceof GrVariable && !(child instanceof GrParameter)) { - defintions.add(((GrVariable) child)); + defintions.add((GrVariable) child); } if (!(child instanceof GrClosableBlock)) { collectInnerDefinitions(child, defintions); @@ -401,10 +402,10 @@ public class GroovyMethodInliner implements InlineHandler.Inliner { assert body != null; GrStatement[] statements = body.getStatements(); if (statements.length == 1) { - if (statements[0] instanceof GrExpression) return ((GrExpression) statements[0]); + if (statements[0] instanceof GrExpression) return (GrExpression) statements[0]; if (statements[0] instanceof GrReturnStatement) { GrExpression value = ((GrReturnStatement) statements[0]).getReturnValue(); - if (value == null && (PsiUtil.getSmartReturnType(method) != PsiType.VOID)) { + if (value == null && PsiUtil.getSmartReturnType(method) != PsiType.VOID) { return GroovyPsiElementFactory.getInstance(method.getProject()).createExpressionFromText("null"); } return value; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyActionsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyActionsTest.groovy index 4cde1e085786..5bb933390cb9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyActionsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyActionsTest.groovy @@ -15,13 +15,14 @@ */ package org.jetbrains.plugins.groovy; -import com.intellij.ide.DataManager; -import com.intellij.openapi.actionSystem.IdeActions; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.actionSystem.EditorActionHandler; -import com.intellij.openapi.editor.actionSystem.EditorActionManager; -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; -import org.jetbrains.plugins.groovy.util.TestUtils; + +import com.intellij.ide.DataManager +import com.intellij.openapi.actionSystem.IdeActions +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.actionSystem.EditorActionHandler +import com.intellij.openapi.editor.actionSystem.EditorActionManager +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import org.jetbrains.plugins.groovy.util.TestUtils /** * @author peter @@ -55,6 +56,8 @@ public class GroovyActionsTest extends LightCodeInsightFixtureTestCase { "a.foo(b)" } + public void testSWInCodeBlock() throws Exception {doTestForSelectWord 3} + private void doTestForSelectWord(int count, String input, String expected) throws Exception { myFixture.configureByText("a.groovy", input); selectWord(count) diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java index b5848346b742..466ae8733a0e 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java @@ -60,6 +60,7 @@ public void testArrayType1() throws Throwable { doTest(); } public void testToGenerate1() throws Throwable { doTest(); } public void testVararg1() throws Throwable { doTest(); } public void testInaccessibleConstructor() throws Throwable { doTest(); } + public void testSynchronizedProperty() throws Throwable { doTest(); } public void testCheckedExceptionInConstructorDelegate() throws Throwable { myFixture.addClass("package foo;" + diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy new file mode 100644 index 000000000000..49b049830f29 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy @@ -0,0 +1,323 @@ +package org.jetbrains.plugins.groovy.lang + +import com.intellij.codeInsight.TargetElementUtilBase +import com.intellij.codeInsight.lookup.LookupManager +import com.intellij.codeInsight.navigation.ImplementationSearcher +import com.intellij.openapi.module.Module +import com.intellij.openapi.roots.ContentEntry +import com.intellij.openapi.roots.ModifiableRootModel +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.roots.libraries.Library +import com.intellij.openapi.vfs.JarFileSystem +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiMethod +import com.intellij.testFramework.LightProjectDescriptor +import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import junit.framework.ComparisonFailure +import org.jetbrains.annotations.NotNull +import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod +import org.jetbrains.plugins.groovy.overrideImplement.GroovyOverrideImplementUtil +import org.jetbrains.plugins.groovy.util.TestUtils +import com.intellij.codeInsight.navigation.GotoImplementationHandler + +/** + * @author peter + */ +class GppFunctionalTest extends LightCodeInsightFixtureTestCase { + static def descriptor = new GppProjectDescriptor() + + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return descriptor; + } + + protected void setUp() { + super.setUp() + myFixture.allowTreeAccessForFile JavaPsiFacade.getInstance(project).findClass(Object.name).containingFile.navigationElement.containingFile.virtualFile + } + + public void testCastListToIterable() throws Exception { + myFixture.addClass("class X extends java.util.ArrayList {}") + testAssignability """ +X ints = [239, 4.2d] +""" + } + + public void testCastListToAnything() throws Exception { + testAssignability """ +File f1 = ['path'] +File f2 = ['path', 2, true, 42] +""" + } + + public void testCastMapToAnotherMap() throws Exception { + myFixture.addClass """ +public class Y extends java.util.HashMap { + public Y(initialCapacity) { + super(initialCapacity); + } +} +""" + + testAssignability """ +HashMap m1 = ['a':['b']] +Y y = [a:'b'] +""" + } + + public void testAnonymousClass() throws Exception { + testAssignability """ +def x = new Object() { + def foo() { + HashMap m1 = ['a':['b']] + HashMap m2 = new File('aaa') + } +} +""" + } + + public void testCastMapToObject() throws Exception { + myFixture.addClass("class Foo { String name; void foo() {} }") + testAssignability """ +Foo f = [name: 'aaa', foo: { println 'hi' }, anotherProperty: 42 ] +""" + } + + void testAssignability(String text) { + myFixture.enableInspections new GroovyAssignabilityCheckInspection() + PsiFile file = configureTyped(text) + myFixture.testHighlighting(true, false, false, file.virtualFile) + } + + private PsiFile configureTyped(String text) { + return myFixture.configureByText("a.groovy", """ +@Typed def foo() { + $text +}""") + } + + public void testDeclaredVariableTypeIsMoreImportantThanTheInitializerOne() throws Exception { + configureTyped(""" +File f = ['path'] +f.mk +""") + myFixture.completeBasic() + assertSameElements myFixture.lookupElementStrings, "mkdir", "mkdirs" + } + + public void testDeclaredVariableTypeIsMoreImportantThanTheInitializerOne2() throws Exception { + myFixture.addClass """ +public class Some { + public int prop + + public void f_foo() {} + public void f_bar() {} +} +""" + + configureTyped(""" +Some s = [prop: 239] +s.f_ +""") + myFixture.completeBasic() + assertSameElements myFixture.lookupElementStrings, "f_foo", "f_bar" + } + + public void testResolveMethod() throws Exception { + myFixture.configureByText("a.groovy", """ +def foo(File f) {} +@Typed def bar() { + foo(['path']) +} +""") + def reference = myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset) + def target = reference.resolve() + assertEquals "foo", ((GrMethod)target).name + } + + public void testOverloadingWithConversion() throws Exception { + myFixture.configureByText("a.groovy", """ +def foo(List l) {} +def foo(File f) {} +@Typed def bar() { + foo(['path']) +} +""") + def reference = myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset) + def target = reference.resolve() + assertNotNull target + assert target.text.contains("List l") + } + + public void testCastClosureToOneMethodClass() throws Exception { + myFixture.addClass """ +public abstract class Foo { + public abstract void foo(String s); + public abstract void bar(String s); +} +public interface Action { + void act(); +} +""" + + testAssignability """ +Foo f = { println it } +Function1 f1 = { println it } +Function1 f2 = { x=42 -> println x } +Function1 f3 = { int x -> println x } +Runnable r = { println it } +Action a = { println it } +Action a1 = { a = 2 -> println a } +""" + } + + public void testClosureParameterTypesInAssignment() throws Exception { + configureTyped "Function1 f = { it.subs }" + myFixture.completeBasic() + assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring" + } + + public void testClosureParameterTypesInMethodInvocation() throws Exception { + myFixture.configureByText "a.groovy", """ +def foo(int a = 1, Function1 f) {} +def foo(String s) {} +def foo(Function2 f) {} + +@Typed def bar() { + foo { it.subsREF } + foo(1, { it.subsREF }) + foo 1, { it.subsREF } + foo(1) { it.subsREF } + foo { a -> a.subsREF } + foo { a, int b=2 -> a.subsREF } + foo { a, b -> b.subsREF } +} +""" + def text = myFixture.file.text + def pos = 0 + while (true) { + pos = text.indexOf("REF", pos+1) + if (pos < 0) { + break + } + myFixture.editor.caretModel.moveToOffset pos + myFixture.completeBasic() + try { + assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring" + } + catch (ComparisonFailure ex) { + println "at: " + text[0.." + text[pos.. bar() { + { it.subs } +} +""" + myFixture.completeBasic() + assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring" + } + + public void testClosureInMapInstantiation() throws Exception { + myFixture.configureByText "a.groovy", """ +class Foo { + int foo(T a) {} +} + +@Typed Foo bar() { + return [foo: { it.subs }] +} +""" + myFixture.completeBasic() + assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring" + } + + public void testClosureInListInstantiation() throws Exception { + myFixture.configureByText "a.groovy", """ +class Foo { + def Foo(int a, Function1 f) {} +} + +@Typed Foo foo() { + [239, { s -> s.subs }] +} +""" + myFixture.completeBasic() + assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring" + } + + public void testTraitHighlighting() throws Exception { + myFixture.configureByText "a.groovy", """ +@Trait +abstract class Intf { + abstract void foo() + void bar() {} +} +class Foo implements Intf {} +class Wrong extends Foo {} +class Bar implements Intf { + void foo() {} +} +""" + myFixture.testHighlighting(true, false, false, myFixture.file.virtualFile) + } + + public void testTraitImplementingAndNavigation() throws Exception { + myFixture.configureByText "a.groovy", """ +@Trait +abstract class Intf { + abstract void foo() + void bar() {} +} +class Foo implements Intf {} +class Bar implements Intf { + void foo() {} +} +class BarImpl extends Bar {} +""" + def facade = JavaPsiFacade.getInstance(getProject()) + assertOneElement(GroovyOverrideImplementUtil.getMethodsToOverrideImplement(facade.findClass("Foo"), true)) + + GrTypeDefinition barClass = facade.findClass("Bar") + assertEmpty(GroovyOverrideImplementUtil.getMethodsToOverrideImplement(barClass, true)) + assertTrue "bar" in GroovyOverrideImplementUtil.getMethodsToOverrideImplement(barClass, false).collect { ((PsiMethod) it.element).name } + + assertEmpty(GroovyOverrideImplementUtil.getMethodsToOverrideImplement(facade.findClass("BarImpl"), true)) + + def implementations = new GotoImplementationHandler().getSourceAndTargetElements(myFixture.editor, myFixture.file).second + assertEquals Arrays.toString(implementations), 3, implementations.size() + } + + public void testResolveToStdLib() throws Exception { + configureTyped """ +@Typed def foo(List l) { + l.each { l.substring(1) } +} +""" + PsiMethod method = myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset).resolve().navigationElement + assertEquals "each", method.name + assertEquals "groovy.util.Iterations", method.containingClass.qualifiedName + } + +} + +class GppProjectDescriptor extends DefaultLightProjectDescriptor { + @Override + public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) { + final Library.ModifiableModel modifiableModel = model.getModuleLibraryTable().createLibrary("GROOVY++").getModifiableModel(); + modifiableModel.addRoot(JarFileSystem.instance.refreshAndFindFileByPath(TestUtils.absoluteTestDataPath + "mockGroovypp/groovypp-0.2.3.jar!/"), OrderRootType.CLASSES); + modifiableModel.addRoot(JarFileSystem.instance.refreshAndFindFileByPath(TestUtils.mockGroovy1_7LibraryName + "!/"), OrderRootType.CLASSES); + modifiableModel.commit(); + } +} \ No newline at end of file diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/RenameTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/RenameTest.groovy index 80febd1b1548..bc2219ac3906 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/RenameTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/RenameTest.groovy @@ -6,11 +6,14 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import com.intellij.psi.PsiReference import com.intellij.psi.impl.source.PostprocessReformattingAspect +import com.intellij.psi.util.PsiTreeUtil import com.intellij.refactoring.rename.RenameProcessor +import com.intellij.refactoring.rename.RenameUtil import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import org.jetbrains.plugins.groovy.GroovyFileType import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod import org.jetbrains.plugins.groovy.util.TestUtils /** @@ -115,4 +118,22 @@ NewClass c = new NewClass() return newName; } + public void testDontAutoRenameDynamicallyTypeUsage() throws Exception { + myFixture.configureByText "a.groovy", """ +class Goo { + def pproject() {} +} + +new Goo().pproject() + +def foo(p) { + p.pproject() +} +""" + def method = PsiTreeUtil.findElementOfClassAtOffset(myFixture.file, myFixture.editor.caretModel.offset, GrMethod.class, false) + def usages = RenameUtil.findUsages(method, "project", false, false, [method:"project"]) + assert !usages[0].isNonCodeUsage + assert usages[1].isNonCodeUsage + } + } diff --git a/plugins/groovy/testdata/groovy/actions/SWInCodeBlock.groovy b/plugins/groovy/testdata/groovy/actions/SWInCodeBlock.groovy new file mode 100644 index 000000000000..5bfcfcd98076 --- /dev/null +++ b/plugins/groovy/testdata/groovy/actions/SWInCodeBlock.groovy @@ -0,0 +1,8 @@ +def foo() { + + //sdjhfksd + print a; + + print b; + +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/actions/SWInCodeBlock_after.groovy b/plugins/groovy/testdata/groovy/actions/SWInCodeBlock_after.groovy new file mode 100644 index 000000000000..cc3bb16ebe71 --- /dev/null +++ b/plugins/groovy/testdata/groovy/actions/SWInCodeBlock_after.groovy @@ -0,0 +1,8 @@ +def foo() { + + //sdjhfksd + print a; + + print b; + +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/stubGenerator/synchronizedProperty.test b/plugins/groovy/testdata/groovy/stubGenerator/synchronizedProperty.test new file mode 100644 index 000000000000..11aaea30e18f --- /dev/null +++ b/plugins/groovy/testdata/groovy/stubGenerator/synchronizedProperty.test @@ -0,0 +1,36 @@ +class Foo { + synchronized def bar +} +----- +public class Foo implements groovy.lang.GroovyObject { + public java.lang.Object getBar() { + return null; + } + + public void setBar(java.lang.Object bar) { + return ; + } + + public groovy.lang.MetaClass getMetaClass() { + return null; + } + + public void setMetaClass(groovy.lang.MetaClass mc) { + return ; + } + + public java.lang.Object invokeMethod(java.lang.String name, java.lang.Object args) { + return null; + } + + public java.lang.Object getProperty(java.lang.String propertyName) { + return null; + } + + public void setProperty(java.lang.String propertyName, java.lang.Object newValue) { + return ; + } + + private java.lang.Object bar = null; +} +--- \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/DuplicateMapKeys.groovy b/plugins/groovy/testdata/highlighting/DuplicateMapKeys.groovy index ea162db4a8fa..31611153ece2 100644 --- a/plugins/groovy/testdata/highlighting/DuplicateMapKeys.groovy +++ b/plugins/groovy/testdata/highlighting/DuplicateMapKeys.groovy @@ -1,2 +1,2 @@ x = [ (person.firstNameKey):person.firstName, (person.lastNameKey):person.lastName ] -x = [2:1, 2:2] \ No newline at end of file +x = ['2':1, '2':2] \ No newline at end of file diff --git a/plugins/groovy/testdata/mockGroovypp/groovypp-0.2.3.jar b/plugins/groovy/testdata/mockGroovypp/groovypp-0.2.3.jar new file mode 100644 index 000000000000..7b84d694dd0c Binary files /dev/null and b/plugins/groovy/testdata/mockGroovypp/groovypp-0.2.3.jar differ diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/I18nInspection.java b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/I18nInspection.java index f9cc459a36a7..d3f727bec3d9 100644 --- a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/I18nInspection.java +++ b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/I18nInspection.java @@ -40,10 +40,7 @@ import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.MethodSignature; -import com.intellij.psi.util.MethodSignatureUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.*; import com.intellij.refactoring.introduceField.IntroduceConstantHandler; import com.intellij.ui.AddDeleteListPanel; import com.intellij.ui.DocumentAdapter; @@ -689,19 +686,7 @@ public class I18nInspection extends BaseLocalInspectionTool { if (parent instanceof PsiExpressionList) { final PsiElement grParent = parent.getParent(); if (grParent instanceof PsiMethodCallExpression) { - final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)grParent).getMethodExpression(); - final PsiExpression qualifier = methodExpression.getQualifierExpression(); - if (qualifier instanceof PsiReferenceExpression) { - final PsiElement resolved = ((PsiReferenceExpression)qualifier).resolve(); - if (resolved instanceof PsiModifierListOwner) { - final PsiModifierListOwner modifierListOwner = (PsiModifierListOwner)resolved; - if (annotatedAsNonNls(modifierListOwner)) { - return true; - } - nonNlsTargets.add(modifierListOwner); - return false; - } - } + return isNonNlsCall((PsiMethodCallExpression)grParent, nonNlsTargets); } else if (grParent instanceof PsiNewExpression) { final PsiElement parentOfNew = grParent.getParent(); @@ -733,6 +718,28 @@ public class I18nInspection extends BaseLocalInspectionTool { return false; } + private static boolean isNonNlsCall(PsiMethodCallExpression grParent, Set nonNlsTargets) { + final PsiReferenceExpression methodExpression = grParent.getMethodExpression(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier instanceof PsiReferenceExpression) { + final PsiElement resolved = ((PsiReferenceExpression)qualifier).resolve(); + if (resolved instanceof PsiModifierListOwner) { + final PsiModifierListOwner modifierListOwner = (PsiModifierListOwner)resolved; + if (annotatedAsNonNls(modifierListOwner)) { + return true; + } + nonNlsTargets.add(modifierListOwner); + return false; + } + } else if (qualifier instanceof PsiMethodCallExpression) { + final PsiType type = qualifier.getType(); + if (type != null && type.equals(methodExpression.getType())) { + return isNonNlsCall((PsiMethodCallExpression)qualifier, nonNlsTargets); + } + } + return false; + } + private static boolean isReturnedFromNonNlsMethod(final PsiLiteralExpression expression, final Set nonNlsTargets) { final PsiElement returnStmt = PsiTreeUtil.getParentOfType(expression, PsiReturnStatement.class, PsiMethodCallExpression.class); diff --git a/plugins/junit/src/com/intellij/execution/junit/TestPackage.java b/plugins/junit/src/com/intellij/execution/junit/TestPackage.java index e500df20e125..d56a1242fdc1 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestPackage.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestPackage.java @@ -21,6 +21,7 @@ import com.intellij.execution.configurations.ConfigurationPerRunnerSettings; import com.intellij.execution.configurations.RunnerSettings; import com.intellij.execution.configurations.RuntimeConfigurationException; import com.intellij.execution.configurations.RuntimeConfigurationWarning; +import com.intellij.execution.runners.ProgramRunner; import com.intellij.execution.testframework.SourceScope; import com.intellij.execution.testframework.TestSearchScope; import com.intellij.openapi.application.ApplicationManager; @@ -49,6 +50,8 @@ import java.net.Socket; import java.util.Collection; public class TestPackage extends TestObject { + private static BackgroundableProcessIndicator mySearchForTestsIndicator; + public TestPackage(final Project project, final JUnitConfiguration configuration, RunnerSettings runnerSettings, @@ -62,6 +65,19 @@ public class TestPackage extends TestObject { return data.getScope().getSourceScope(myConfiguration); } + @Override + public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner) throws ExecutionException { + try { + return super.execute(executor, runner); + } + catch (ExecutionException e) { + if (mySearchForTestsIndicator != null && !mySearchForTestsIndicator.isCanceled()) { + mySearchForTestsIndicator.cancel(); //ensure that search for tests stops anyway + } + throw e; + } + } + protected void initialize() throws ExecutionException { super.initialize(); final Project project = myConfiguration.getProject(); @@ -244,7 +260,7 @@ public class TestPackage extends TestObject { } } }; - ProgressManagerImpl.runProcessWithProgressAsynchronously(task, new BackgroundableProcessIndicator(task) { + mySearchForTestsIndicator = new BackgroundableProcessIndicator(task) { @Override public void cancel() { try {//ensure that serverSocket.accept was interrupted @@ -257,7 +273,8 @@ public class TestPackage extends TestObject { } super.cancel(); } - }); + }; + ProgressManagerImpl.runProcessWithProgressAsynchronously(task, mySearchForTestsIndicator); } private static boolean isSyncSearch() { diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/ArtifactType.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/ArtifactType.java new file mode 100644 index 000000000000..3614bccf3caf --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/ArtifactType.java @@ -0,0 +1,368 @@ + +/* + * Copyright 2000-2010 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.idea.maven.facade.nexus; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.io.Serializable; + + +/** + *

    Java class for artifactType complex type. + * + *

    The following schema fragment specifies the expected content contained within this class. + * + *

    + * <complexType name="artifactType">
    + *   <complexContent>
    + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    + *       <sequence>
    + *         <element name="resourceUri" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="groupId" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="artifactId" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="version" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="classifier" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="packaging" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="extension" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="repoId" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="contextId" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="pomLink" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="artifactLink" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *       </sequence>
    + *     </restriction>
    + *   </complexContent>
    + * </complexType>
    + * 
    + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "artifactType", propOrder = { + "resourceUri", + "groupId", + "artifactId", + "version", + "classifier", + "packaging", + "extension", + "repoId", + "contextId", + "pomLink", + "artifactLink" +}) +public class ArtifactType implements Serializable { + + @XmlElement(required = true) + protected String resourceUri; + @XmlElement(required = true) + protected String groupId; + @XmlElement(required = true) + protected String artifactId; + @XmlElement(required = true) + protected String version; + @XmlElement(required = true) + protected String classifier; + @XmlElement(required = true) + protected String packaging; + @XmlElement(required = true) + protected String extension; + @XmlElement(required = true) + protected String repoId; + @XmlElement(required = true) + protected String contextId; + @XmlElement(required = true) + protected String pomLink; + @XmlElement(required = true) + protected String artifactLink; + + public ArtifactType() { + + } + + public ArtifactType(String groupId, String artifactId, String version) { + this.groupId = groupId; + this.artifactId = artifactId; + this.version = version; + } + + /** + * Gets the value of the resourceUri property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getResourceUri() { + return resourceUri; + } + + /** + * Sets the value of the resourceUri property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setResourceUri(String value) { + this.resourceUri = value; + } + + /** + * Gets the value of the groupId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getGroupId() { + return groupId; + } + + /** + * Sets the value of the groupId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setGroupId(String value) { + this.groupId = value; + } + + /** + * Gets the value of the artifactId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getArtifactId() { + return artifactId; + } + + /** + * Sets the value of the artifactId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setArtifactId(String value) { + this.artifactId = value; + } + + /** + * Gets the value of the version property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getVersion() { + return version; + } + + /** + * Sets the value of the version property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setVersion(String value) { + this.version = value; + } + + /** + * Gets the value of the classifier property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getClassifier() { + return classifier; + } + + /** + * Sets the value of the classifier property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setClassifier(String value) { + this.classifier = value; + } + + /** + * Gets the value of the packaging property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getPackaging() { + return packaging; + } + + /** + * Sets the value of the packaging property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setPackaging(String value) { + this.packaging = value; + } + + /** + * Gets the value of the extension property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getExtension() { + return extension; + } + + /** + * Sets the value of the extension property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setExtension(String value) { + this.extension = value; + } + + /** + * Gets the value of the repoId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getRepoId() { + return repoId; + } + + /** + * Sets the value of the repoId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setRepoId(String value) { + this.repoId = value; + } + + /** + * Gets the value of the contextId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getContextId() { + return contextId; + } + + /** + * Sets the value of the contextId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setContextId(String value) { + this.contextId = value; + } + + /** + * Gets the value of the pomLink property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getPomLink() { + return pomLink; + } + + /** + * Sets the value of the pomLink property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setPomLink(String value) { + this.pomLink = value; + } + + /** + * Gets the value of the artifactLink property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getArtifactLink() { + return artifactLink; + } + + /** + * Sets the value of the artifactLink property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setArtifactLink(String value) { + this.artifactLink = value; + } + +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/Endpoint.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/Endpoint.java new file mode 100644 index 000000000000..c568d82b5dcb --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/Endpoint.java @@ -0,0 +1,288 @@ + +/* + * Copyright 2000-2010 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.idea.maven.facade.nexus; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.List; +import javax.activation.DataSource; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import org.jvnet.ws.wadl.util.DSDispatcher; +import org.jvnet.ws.wadl.util.JAXBDispatcher; +import org.jvnet.ws.wadl.util.UriBuilder; + +public class Endpoint { + + + public static class DataIndex { + + private JAXBDispatcher _jaxbDispatcher; + private DSDispatcher _dsDispatcher; + private UriBuilder _uriBuilder; + private JAXBContext _jc; + private HashMap _templateAndMatrixParameterValues; + + /** + * Create new instance + * + * @param nexusRoot + */ + public DataIndex(final String nexusRoot) + throws JAXBException + { + _jc = JAXBContext.newInstance("org.jetbrains.idea.maven.facade.nexus"); + _jaxbDispatcher = new JAXBDispatcher(_jc); + _dsDispatcher = new DSDispatcher(); + _uriBuilder = new UriBuilder(); + List _matrixParamSet; + _matrixParamSet = _uriBuilder.addPathSegment(nexusRoot); + _matrixParamSet = _uriBuilder.addPathSegment("data_index"); + _templateAndMatrixParameterValues = new HashMap(); + } + + public DataSource getArtifactlistAsApplicationXml() + throws IOException, MalformedURLException + { + HashMap _queryParameterValues = new HashMap(); + HashMap _headerParameterValues = new HashMap(); + String _url = _uriBuilder.buildUri(_templateAndMatrixParameterValues, _queryParameterValues); + DataSource _retVal = _dsDispatcher.doGET(_url, _headerParameterValues, "application/xml"); + return _retVal; + } + + public SearchResults getArtifactlistAsSearchResults() + throws IOException, MalformedURLException, JAXBException + { + HashMap _queryParameterValues = new HashMap(); + HashMap _headerParameterValues = new HashMap(); + String _url = _uriBuilder.buildUri(_templateAndMatrixParameterValues, _queryParameterValues); + Object _retVal = _jaxbDispatcher.doGET(_url, _headerParameterValues, "application/xml"); + if (_retVal == null) { + return null; + } + if (JAXBElement.class.isInstance(_retVal)) { + JAXBElement jaxbElement = ((JAXBElement) _retVal); + _retVal = jaxbElement.getValue(); + } + return ((SearchResults) _retVal); + } + + public DataSource getArtifactlistAsApplicationXml(String q, String g, String a, String v, String c) + throws IOException, MalformedURLException + { + HashMap _queryParameterValues = new HashMap(); + HashMap _headerParameterValues = new HashMap(); + _queryParameterValues.put("q", q); + _queryParameterValues.put("g", g); + _queryParameterValues.put("a", a); + _queryParameterValues.put("v", v); + _queryParameterValues.put("c", c); + String _url = _uriBuilder.buildUri(_templateAndMatrixParameterValues, _queryParameterValues); + DataSource _retVal = _dsDispatcher.doGET(_url, _headerParameterValues, "application/xml"); + return _retVal; + } + + public SearchResults getArtifactlistAsSearchResults(String q, String g, String a, String v, String c) + throws IOException, MalformedURLException, JAXBException + { + HashMap _queryParameterValues = new HashMap(); + HashMap _headerParameterValues = new HashMap(); + _queryParameterValues.put("q", q); + _queryParameterValues.put("g", g); + _queryParameterValues.put("a", a); + _queryParameterValues.put("v", v); + _queryParameterValues.put("c", c); + String _url = _uriBuilder.buildUri(_templateAndMatrixParameterValues, _queryParameterValues); + Object _retVal = _jaxbDispatcher.doGET(_url, _headerParameterValues, "application/xml"); + if (_retVal == null) { + return null; + } + if (JAXBElement.class.isInstance(_retVal)) { + JAXBElement jaxbElement = ((JAXBElement) _retVal); + _retVal = jaxbElement.getValue(); + } + return ((SearchResults) _retVal); + } + + } + + public static class DataIndexRepository { + + private JAXBDispatcher _jaxbDispatcher; + private DSDispatcher _dsDispatcher; + private UriBuilder _uriBuilder; + private JAXBContext _jc; + private HashMap _templateAndMatrixParameterValues; + + /** + * Create new instance + * + */ + public DataIndexRepository(String repository) + throws JAXBException + { + _jc = JAXBContext.newInstance("org.jetbrains.idea.maven.facade.nexus"); + _jaxbDispatcher = new JAXBDispatcher(_jc); + _dsDispatcher = new DSDispatcher(); + _uriBuilder = new UriBuilder(); + List _matrixParamSet; + _matrixParamSet = _uriBuilder.addPathSegment("http://repository.sonatype.org/service/local/"); + _matrixParamSet = _uriBuilder.addPathSegment("data_index/{repository}"); + _templateAndMatrixParameterValues = new HashMap(); + _templateAndMatrixParameterValues.put("repository", repository); + } + + /** + * Get repository + * + */ + public String getRepository() { + return ((String) _templateAndMatrixParameterValues.get("repository")); + } + + /** + * Set repository + * + */ + public void setRepository(String repository) { + _templateAndMatrixParameterValues.put("repository", repository); + } + + public DataSource getArtifactlistAsApplicationXml() + throws IOException, MalformedURLException + { + HashMap _queryParameterValues = new HashMap(); + HashMap _headerParameterValues = new HashMap(); + String _url = _uriBuilder.buildUri(_templateAndMatrixParameterValues, _queryParameterValues); + DataSource _retVal = _dsDispatcher.doGET(_url, _headerParameterValues, "application/xml"); + return _retVal; + } + + public SearchResults getArtifactlistAsSearchResults() + throws IOException, MalformedURLException, JAXBException + { + HashMap _queryParameterValues = new HashMap(); + HashMap _headerParameterValues = new HashMap(); + String _url = _uriBuilder.buildUri(_templateAndMatrixParameterValues, _queryParameterValues); + Object _retVal = _jaxbDispatcher.doGET(_url, _headerParameterValues, "application/xml"); + if (_retVal == null) { + return null; + } + if (JAXBElement.class.isInstance(_retVal)) { + JAXBElement jaxbElement = ((JAXBElement) _retVal); + _retVal = jaxbElement.getValue(); + } + return ((SearchResults) _retVal); + } + + public DataSource getArtifactlistAsApplicationXml(String q, String g, String a, String v, String c) + throws IOException, MalformedURLException + { + HashMap _queryParameterValues = new HashMap(); + HashMap _headerParameterValues = new HashMap(); + _queryParameterValues.put("q", q); + _queryParameterValues.put("g", g); + _queryParameterValues.put("a", a); + _queryParameterValues.put("v", v); + _queryParameterValues.put("c", c); + String _url = _uriBuilder.buildUri(_templateAndMatrixParameterValues, _queryParameterValues); + DataSource _retVal = _dsDispatcher.doGET(_url, _headerParameterValues, "application/xml"); + return _retVal; + } + + public SearchResults getArtifactlistAsSearchResults(String q, String g, String a, String v, String c) + throws IOException, MalformedURLException, JAXBException + { + HashMap _queryParameterValues = new HashMap(); + HashMap _headerParameterValues = new HashMap(); + _queryParameterValues.put("q", q); + _queryParameterValues.put("g", g); + _queryParameterValues.put("a", a); + _queryParameterValues.put("v", v); + _queryParameterValues.put("c", c); + String _url = _uriBuilder.buildUri(_templateAndMatrixParameterValues, _queryParameterValues); + Object _retVal = _jaxbDispatcher.doGET(_url, _headerParameterValues, "application/xml"); + if (_retVal == null) { + return null; + } + if (JAXBElement.class.isInstance(_retVal)) { + JAXBElement jaxbElement = ((JAXBElement) _retVal); + _retVal = jaxbElement.getValue(); + } + return ((SearchResults) _retVal); + } + + } + + public static class Repositories { + + private JAXBDispatcher _jaxbDispatcher; + private DSDispatcher _dsDispatcher; + private UriBuilder _uriBuilder; + private JAXBContext _jc; + private HashMap _templateAndMatrixParameterValues; + + /** + * Create new instance + * + */ + public Repositories() + throws JAXBException + { + _jc = JAXBContext.newInstance("org.jetbrains.idea.maven.facade.nexus"); + _jaxbDispatcher = new JAXBDispatcher(_jc); + _dsDispatcher = new DSDispatcher(); + _uriBuilder = new UriBuilder(); + List _matrixParamSet; + _matrixParamSet = _uriBuilder.addPathSegment("http://repository.sonatype.org/service/local/"); + _matrixParamSet = _uriBuilder.addPathSegment("repositories"); + _templateAndMatrixParameterValues = new HashMap(); + } + + public DataSource getRepolistAsApplicationXml() + throws IOException, MalformedURLException + { + HashMap _queryParameterValues = new HashMap(); + HashMap _headerParameterValues = new HashMap(); + String _url = _uriBuilder.buildUri(_templateAndMatrixParameterValues, _queryParameterValues); + DataSource _retVal = _dsDispatcher.doGET(_url, _headerParameterValues, "application/xml"); + return _retVal; + } + + public Repositories getRepolistAsRepositories() + throws IOException, MalformedURLException, JAXBException + { + HashMap _queryParameterValues = new HashMap(); + HashMap _headerParameterValues = new HashMap(); + String _url = _uriBuilder.buildUri(_templateAndMatrixParameterValues, _queryParameterValues); + Object _retVal = _jaxbDispatcher.doGET(_url, _headerParameterValues, "application/xml"); + if (_retVal == null) { + return null; + } + if (JAXBElement.class.isInstance(_retVal)) { + JAXBElement jaxbElement = ((JAXBElement) _retVal); + _retVal = jaxbElement.getValue(); + } + return ((Repositories) _retVal); + } + + } + +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/ObjectFactory.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/ObjectFactory.java new file mode 100644 index 000000000000..cd6d3df8eba7 --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/ObjectFactory.java @@ -0,0 +1,103 @@ + +/* + * Copyright 2000-2010 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.idea.maven.facade.nexus; + +import javax.xml.bind.annotation.XmlRegistry; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the nexus package. + *

    An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: nexus + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link Repositories } + * + */ + public Repositories createRepositories() { + return new Repositories(); + } + + /** + * Create an instance of {@link RepositoryMetaData } + * + */ + public RepositoryMetaData createRepositoryMetaData() { + return new RepositoryMetaData(); + } + + /** + * Create an instance of {@link SearchResults } + * + */ + public SearchResults createSearchResults() { + return new SearchResults(); + } + + /** + * Create an instance of {@link RepositoryType } + * + */ + public RepositoryType createRepositoryType() { + return new RepositoryType(); + } + + /** + * Create an instance of {@link ArtifactType } + * + */ + public ArtifactType createArtifactType() { + return new ArtifactType(); + } + + /** + * Create an instance of {@link Repositories.Data } + * + */ + public Repositories.Data createRepositoriesData() { + return new Repositories.Data(); + } + + /** + * Create an instance of {@link SearchResults.Data } + * + */ + public SearchResults.Data createSearchResultsData() { + return new SearchResults.Data(); + } + +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/Repositories.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/Repositories.java new file mode 100644 index 000000000000..178e258a0512 --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/Repositories.java @@ -0,0 +1,151 @@ + +/* + * Copyright 2000-2010 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.idea.maven.facade.nexus; + +import java.util.ArrayList; +import java.util.List; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

    Java class for anonymous complex type. + * + *

    The following schema fragment specifies the expected content contained within this class. + * + *

    + * <complexType>
    + *   <complexContent>
    + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    + *       <sequence>
    + *         <element name="data">
    + *           <complexType>
    + *             <complexContent>
    + *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    + *                 <sequence>
    + *                   <element name="repositories-item" type="{}repositoryType" maxOccurs="unbounded" minOccurs="0"/>
    + *                 </sequence>
    + *               </restriction>
    + *             </complexContent>
    + *           </complexType>
    + *         </element>
    + *       </sequence>
    + *     </restriction>
    + *   </complexContent>
    + * </complexType>
    + * 
    + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "data" +}) +@XmlRootElement(name = "repositories") +public class Repositories { + + @XmlElement(required = true) + protected Repositories.Data data; + + /** + * Gets the value of the data property. + * + * @return + * possible object is + * {@link Repositories.Data } + * + */ + public Repositories.Data getData() { + return data; + } + + /** + * Sets the value of the data property. + * + * @param value + * allowed object is + * {@link Repositories.Data } + * + */ + public void setData(Repositories.Data value) { + this.data = value; + } + + + /** + *

    Java class for anonymous complex type. + * + *

    The following schema fragment specifies the expected content contained within this class. + * + *

    +     * <complexType>
    +     *   <complexContent>
    +     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    +     *       <sequence>
    +     *         <element name="repositories-item" type="{}repositoryType" maxOccurs="unbounded" minOccurs="0"/>
    +     *       </sequence>
    +     *     </restriction>
    +     *   </complexContent>
    +     * </complexType>
    +     * 
    + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "repositoriesItem" + }) + public static class Data { + + @XmlElement(name = "repositories-item") + protected List repositoriesItem; + + /** + * Gets the value of the repositoriesItem property. + * + *

    + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the repositoriesItem property. + * + *

    + * For example, to add a new item, do as follows: + *

    +         *    getRepositoriesItem().add(newItem);
    +         * 
    + * + * + *

    + * Objects of the following type(s) are allowed in the list + * {@link RepositoryType } + * + * + */ + public List getRepositoriesItem() { + if (repositoriesItem == null) { + repositoriesItem = new ArrayList(); + } + return this.repositoriesItem; + } + + } + +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/RepositoryMetaData.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/RepositoryMetaData.java new file mode 100644 index 000000000000..2516734256cd --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/RepositoryMetaData.java @@ -0,0 +1,220 @@ + +/* + * Copyright 2000-2010 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.idea.maven.facade.nexus; + +import java.math.BigInteger; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

    Java class for anonymous complex type. + * + *

    The following schema fragment specifies the expected content contained within this class. + * + *

    + * <complexType>
    + *   <complexContent>
    + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    + *       <sequence>
    + *         <element name="id" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="repoType" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="effectiveLocalStorageUrl" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="proxyUrl" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="sizeOnDisk" type="{http://www.w3.org/2001/XMLSchema}integer"/>
    + *         <element name="numArtifacts" type="{http://www.w3.org/2001/XMLSchema}integer"/>
    + *       </sequence>
    + *     </restriction>
    + *   </complexContent>
    + * </complexType>
    + * 
    + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "id", + "repoType", + "effectiveLocalStorageUrl", + "proxyUrl", + "sizeOnDisk", + "numArtifacts" +}) +@XmlRootElement(name = "repositoryMetaData") +public class RepositoryMetaData { + + @XmlElement(required = true) + protected String id; + @XmlElement(required = true) + protected String repoType; + @XmlElement(required = true) + protected String effectiveLocalStorageUrl; + @XmlElement(required = true) + protected String proxyUrl; + @XmlElement(required = true) + protected BigInteger sizeOnDisk; + @XmlElement(required = true) + protected BigInteger numArtifacts; + + /** + * Gets the value of the id property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getId() { + return id; + } + + /** + * Sets the value of the id property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setId(String value) { + this.id = value; + } + + /** + * Gets the value of the repoType property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getRepoType() { + return repoType; + } + + /** + * Sets the value of the repoType property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setRepoType(String value) { + this.repoType = value; + } + + /** + * Gets the value of the effectiveLocalStorageUrl property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getEffectiveLocalStorageUrl() { + return effectiveLocalStorageUrl; + } + + /** + * Sets the value of the effectiveLocalStorageUrl property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setEffectiveLocalStorageUrl(String value) { + this.effectiveLocalStorageUrl = value; + } + + /** + * Gets the value of the proxyUrl property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getProxyUrl() { + return proxyUrl; + } + + /** + * Sets the value of the proxyUrl property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setProxyUrl(String value) { + this.proxyUrl = value; + } + + /** + * Gets the value of the sizeOnDisk property. + * + * @return + * possible object is + * {@link BigInteger } + * + */ + public BigInteger getSizeOnDisk() { + return sizeOnDisk; + } + + /** + * Sets the value of the sizeOnDisk property. + * + * @param value + * allowed object is + * {@link BigInteger } + * + */ + public void setSizeOnDisk(BigInteger value) { + this.sizeOnDisk = value; + } + + /** + * Gets the value of the numArtifacts property. + * + * @return + * possible object is + * {@link BigInteger } + * + */ + public BigInteger getNumArtifacts() { + return numArtifacts; + } + + /** + * Sets the value of the numArtifacts property. + * + * @param value + * allowed object is + * {@link BigInteger } + * + */ + public void setNumArtifacts(BigInteger value) { + this.numArtifacts = value; + } + +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/RepositoryType.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/RepositoryType.java new file mode 100644 index 000000000000..bd744208670f --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/RepositoryType.java @@ -0,0 +1,385 @@ + +/* + * Copyright 2000-2010 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.idea.maven.facade.nexus; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

    Java class for repositoryType complex type. + * + *

    The following schema fragment specifies the expected content contained within this class. + * + *

    + * <complexType name="repositoryType">
    + *   <complexContent>
    + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    + *       <sequence>
    + *         <element name="resourceURI" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="contentResourceURI" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="id" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="repoType" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="repoPolicy" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="provider" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="providerRole" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="format" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="userManaged" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="exposed" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *         <element name="effectiveLocalStorageUrl" type="{http://www.w3.org/2001/XMLSchema}string"/>
    + *       </sequence>
    + *     </restriction>
    + *   </complexContent>
    + * </complexType>
    + * 
    + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "repositoryType", propOrder = { + "resourceURI", + "contentResourceURI", + "id", + "name", + "repoType", + "repoPolicy", + "provider", + "providerRole", + "format", + "userManaged", + "exposed", + "effectiveLocalStorageUrl" +}) +public class RepositoryType { + + @XmlElement(required = true) + protected String resourceURI; + @XmlElement(required = true) + protected String contentResourceURI; + @XmlElement(required = true) + protected String id; + @XmlElement(required = true) + protected String name; + @XmlElement(required = true) + protected String repoType; + @XmlElement(required = true) + protected String repoPolicy; + @XmlElement(required = true) + protected String provider; + @XmlElement(required = true) + protected String providerRole; + @XmlElement(required = true) + protected String format; + @XmlElement(required = true) + protected String userManaged; + @XmlElement(required = true) + protected String exposed; + @XmlElement(required = true) + protected String effectiveLocalStorageUrl; + + /** + * Gets the value of the resourceURI property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getResourceURI() { + return resourceURI; + } + + /** + * Sets the value of the resourceURI property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setResourceURI(String value) { + this.resourceURI = value; + } + + /** + * Gets the value of the contentResourceURI property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getContentResourceURI() { + return contentResourceURI; + } + + /** + * Sets the value of the contentResourceURI property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setContentResourceURI(String value) { + this.contentResourceURI = value; + } + + /** + * Gets the value of the id property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getId() { + return id; + } + + /** + * Sets the value of the id property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setId(String value) { + this.id = value; + } + + /** + * Gets the value of the name property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getName() { + return name; + } + + /** + * Sets the value of the name property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setName(String value) { + this.name = value; + } + + /** + * Gets the value of the repoType property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getRepoType() { + return repoType; + } + + /** + * Sets the value of the repoType property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setRepoType(String value) { + this.repoType = value; + } + + /** + * Gets the value of the repoPolicy property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getRepoPolicy() { + return repoPolicy; + } + + /** + * Sets the value of the repoPolicy property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setRepoPolicy(String value) { + this.repoPolicy = value; + } + + /** + * Gets the value of the provider property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getProvider() { + return provider; + } + + /** + * Sets the value of the provider property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setProvider(String value) { + this.provider = value; + } + + /** + * Gets the value of the providerRole property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getProviderRole() { + return providerRole; + } + + /** + * Sets the value of the providerRole property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setProviderRole(String value) { + this.providerRole = value; + } + + /** + * Gets the value of the format property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getFormat() { + return format; + } + + /** + * Sets the value of the format property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setFormat(String value) { + this.format = value; + } + + /** + * Gets the value of the userManaged property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getUserManaged() { + return userManaged; + } + + /** + * Sets the value of the userManaged property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setUserManaged(String value) { + this.userManaged = value; + } + + /** + * Gets the value of the exposed property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getExposed() { + return exposed; + } + + /** + * Sets the value of the exposed property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setExposed(String value) { + this.exposed = value; + } + + /** + * Gets the value of the effectiveLocalStorageUrl property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getEffectiveLocalStorageUrl() { + return effectiveLocalStorageUrl; + } + + /** + * Sets the value of the effectiveLocalStorageUrl property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setEffectiveLocalStorageUrl(String value) { + this.effectiveLocalStorageUrl = value; + } + +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/SearchResult.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/SearchResult.java new file mode 100644 index 000000000000..7e1c447f5f3c --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/SearchResult.java @@ -0,0 +1,254 @@ + +/* + * Copyright 2000-2010 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.idea.maven.facade.nexus; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

    Java class for anonymous complex type. + * + *

    The following schema fragment specifies the expected content contained within this class. + * + *

    + * <complexType>
    + *   <complexContent>
    + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    + *       <sequence>
    + *         <element name="totalCount" type="{http://www.w3.org/2001/XMLSchema}integer"/>
    + *         <element name="from" type="{http://www.w3.org/2001/XMLSchema}integer"/>
    + *         <element name="count" type="{http://www.w3.org/2001/XMLSchema}integer"/>
    + *         <element name="tooManyResults" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
    + *         <element name="data">
    + *           <complexType>
    + *             <complexContent>
    + *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    + *                 <sequence>
    + *                   <element name="artifact" type="{}artifactType" maxOccurs="unbounded" minOccurs="0"/>
    + *                 </sequence>
    + *               </restriction>
    + *             </complexContent>
    + *           </complexType>
    + *         </element>
    + *       </sequence>
    + *     </restriction>
    + *   </complexContent>
    + * </complexType>
    + * 
    + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "totalCount", + "from", + "count", + "tooManyResults", + "data" +}) +@XmlRootElement(name = "search-result") +public class SearchResult { + + @XmlElement(required = true) + protected BigInteger totalCount; + @XmlElement(required = true) + protected BigInteger from; + @XmlElement(required = true) + protected BigInteger count; + protected boolean tooManyResults; + @XmlElement(required = true) + protected SearchResult.Data data; + + /** + * Gets the value of the totalCount property. + * + * @return + * possible object is + * {@link BigInteger } + * + */ + public BigInteger getTotalCount() { + return totalCount; + } + + /** + * Sets the value of the totalCount property. + * + * @param value + * allowed object is + * {@link BigInteger } + * + */ + public void setTotalCount(BigInteger value) { + this.totalCount = value; + } + + /** + * Gets the value of the from property. + * + * @return + * possible object is + * {@link BigInteger } + * + */ + public BigInteger getFrom() { + return from; + } + + /** + * Sets the value of the from property. + * + * @param value + * allowed object is + * {@link BigInteger } + * + */ + public void setFrom(BigInteger value) { + this.from = value; + } + + /** + * Gets the value of the count property. + * + * @return + * possible object is + * {@link BigInteger } + * + */ + public BigInteger getCount() { + return count; + } + + /** + * Sets the value of the count property. + * + * @param value + * allowed object is + * {@link BigInteger } + * + */ + public void setCount(BigInteger value) { + this.count = value; + } + + /** + * Gets the value of the tooManyResults property. + * + */ + public boolean isTooManyResults() { + return tooManyResults; + } + + /** + * Sets the value of the tooManyResults property. + * + */ + public void setTooManyResults(boolean value) { + this.tooManyResults = value; + } + + /** + * Gets the value of the data property. + * + * @return + * possible object is + * {@link SearchResult.Data } + * + */ + public SearchResult.Data getData() { + return data; + } + + /** + * Sets the value of the data property. + * + * @param value + * allowed object is + * {@link SearchResult.Data } + * + */ + public void setData(SearchResult.Data value) { + this.data = value; + } + + + /** + *

    Java class for anonymous complex type. + * + *

    The following schema fragment specifies the expected content contained within this class. + * + *

    +     * <complexType>
    +     *   <complexContent>
    +     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    +     *       <sequence>
    +     *         <element name="artifact" type="{}artifactType" maxOccurs="unbounded" minOccurs="0"/>
    +     *       </sequence>
    +     *     </restriction>
    +     *   </complexContent>
    +     * </complexType>
    +     * 
    + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "artifact" + }) + public static class Data { + + protected List artifact; + + /** + * Gets the value of the artifact property. + * + *

    + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the artifact property. + * + *

    + * For example, to add a new item, do as follows: + *

    +         *    getArtifact().add(newItem);
    +         * 
    + * + * + *

    + * Objects of the following type(s) are allowed in the list + * {@link ArtifactType } + * + * + */ + public List getArtifact() { + if (artifact == null) { + artifact = new ArrayList(); + } + return this.artifact; + } + + } + +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/SearchResults.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/SearchResults.java new file mode 100644 index 000000000000..6cfe85d0c162 --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/SearchResults.java @@ -0,0 +1,253 @@ + +/* + * Copyright 2000-2010 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.idea.maven.facade.nexus; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

    Java class for anonymous complex type. + * + *

    The following schema fragment specifies the expected content contained within this class. + * + *

    + * <complexType>
    + *   <complexContent>
    + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    + *       <sequence>
    + *         <element name="totalCount" type="{http://www.w3.org/2001/XMLSchema}integer"/>
    + *         <element name="from" type="{http://www.w3.org/2001/XMLSchema}integer"/>
    + *         <element name="count" type="{http://www.w3.org/2001/XMLSchema}integer"/>
    + *         <element name="tooManyResults" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
    + *         <element name="data" minOccurs="0">
    + *           <complexType>
    + *             <complexContent>
    + *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    + *                 <sequence>
    + *                   <element name="artifact" type="{}artifactType" maxOccurs="unbounded" minOccurs="0"/>
    + *                 </sequence>
    + *               </restriction>
    + *             </complexContent>
    + *           </complexType>
    + *         </element>
    + *       </sequence>
    + *     </restriction>
    + *   </complexContent>
    + * </complexType>
    + * 
    + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "totalCount", + "from", + "count", + "tooManyResults", + "data" +}) +@XmlRootElement(name = "search-results") +public class SearchResults { + + @XmlElement(required = true) + protected BigInteger totalCount; + @XmlElement(required = true) + protected BigInteger from; + @XmlElement(required = true) + protected BigInteger count; + protected boolean tooManyResults; + protected SearchResults.Data data; + + /** + * Gets the value of the totalCount property. + * + * @return + * possible object is + * {@link BigInteger } + * + */ + public BigInteger getTotalCount() { + return totalCount; + } + + /** + * Sets the value of the totalCount property. + * + * @param value + * allowed object is + * {@link BigInteger } + * + */ + public void setTotalCount(BigInteger value) { + this.totalCount = value; + } + + /** + * Gets the value of the from property. + * + * @return + * possible object is + * {@link BigInteger } + * + */ + public BigInteger getFrom() { + return from; + } + + /** + * Sets the value of the from property. + * + * @param value + * allowed object is + * {@link BigInteger } + * + */ + public void setFrom(BigInteger value) { + this.from = value; + } + + /** + * Gets the value of the count property. + * + * @return + * possible object is + * {@link BigInteger } + * + */ + public BigInteger getCount() { + return count; + } + + /** + * Sets the value of the count property. + * + * @param value + * allowed object is + * {@link BigInteger } + * + */ + public void setCount(BigInteger value) { + this.count = value; + } + + /** + * Gets the value of the tooManyResults property. + * + */ + public boolean isTooManyResults() { + return tooManyResults; + } + + /** + * Sets the value of the tooManyResults property. + * + */ + public void setTooManyResults(boolean value) { + this.tooManyResults = value; + } + + /** + * Gets the value of the data property. + * + * @return + * possible object is + * {@link SearchResults.Data } + * + */ + public SearchResults.Data getData() { + return data; + } + + /** + * Sets the value of the data property. + * + * @param value + * allowed object is + * {@link SearchResults.Data } + * + */ + public void setData(SearchResults.Data value) { + this.data = value; + } + + + /** + *

    Java class for anonymous complex type. + * + *

    The following schema fragment specifies the expected content contained within this class. + * + *

    +     * <complexType>
    +     *   <complexContent>
    +     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    +     *       <sequence>
    +     *         <element name="artifact" type="{}artifactType" maxOccurs="unbounded" minOccurs="0"/>
    +     *       </sequence>
    +     *     </restriction>
    +     *   </complexContent>
    +     * </complexType>
    +     * 
    + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "artifact" + }) + public static class Data { + + protected List artifact; + + /** + * Gets the value of the artifact property. + * + *

    + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the artifact property. + * + *

    + * For example, to add a new item, do as follows: + *

    +         *    getArtifact().add(newItem);
    +         * 
    + * + * + *

    + * Objects of the following type(s) are allowed in the list + * {@link ArtifactType } + * + * + */ + public List getArtifact() { + if (artifact == null) { + artifact = new ArrayList(); + } + return this.artifact; + } + + } + +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/nexus.wadl b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/nexus.wadl new file mode 100644 index 000000000000..4eb1cc31849d --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/nexus.wadl @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/nexus.xsd b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/nexus.xsd new file mode 100644 index 000000000000..ad51660ef2df --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/nexus/nexus.xsd @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/MavenFacade.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/MavenFacade.java new file mode 100644 index 000000000000..a585d2e168ad --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/MavenFacade.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2010 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.idea.maven.facade.remote; + +import org.jetbrains.idea.maven.facade.nexus.ArtifactType; + +import java.io.Serializable; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author Gregory.Shrago + */ +public interface MavenFacade extends Remote { + + List findArtifacts(ArtifactType template) throws RemoteException; + + Map> resolveDependencies(List artifacts) throws RemoteException; + + void setTransferListener(RemoteTransferListener listener) throws RemoteException; + + void setMavenSettings(MavenFacadeSettings settings) throws RemoteException; + + class MavenFacadeSettings implements Serializable { + private Repository myLocalRepository; + private final List myRemoteRepositories = new ArrayList(); + private final List myNexusUrls = new ArrayList(); + + public Repository getLocalRepository() { + return myLocalRepository; + } + + public void setLocalRepository(Repository localRepository) { + myLocalRepository = localRepository; + } + + public List getRemoteRepositories() { + return myRemoteRepositories; + } + + public List getNexusUrls() { + return myNexusUrls; + } + } + + class Repository implements Serializable { + private String myId; + private String myUrl; + private String myLayout; + + public Repository(String id, String url, String layout) { + myUrl = url; + myId = id; + myLayout = layout; + } + + public String getId() { + return myId; + } + + public void setId(String id) { + myId = id; + } + + public String getUrl() { + return myUrl; + } + + public void setUrl(String url) { + myUrl = url; + } + + public String getLayout() { + return myLayout; + } + + public void setLayout(String layout) { + myLayout = layout; + } + } + +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/MavenFacadeLocator.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/MavenFacadeLocator.java new file mode 100644 index 000000000000..70c3875a4844 --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/MavenFacadeLocator.java @@ -0,0 +1,151 @@ +package org.jetbrains.idea.maven.facade.remote; + +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; +import org.jetbrains.idea.maven.facade.nexus.ArtifactType; + +import java.io.*; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.CharBuffer; +import java.rmi.registry.LocateRegistry; +import java.util.List; + +/** + * @author Gregory.Shrago + */ +public class MavenFacadeLocator { + + private static final String PORT_ID_PREFIX = "Port/ID:"; + + public static Pair acquireFacade(String[] cmdArray, String[] envP, File dir) throws Exception { + final Process process = Runtime.getRuntime().exec(cmdArray, envP, dir); + final Ref> result = Ref.create(null); + final Runnable target = new Runnable() { + public void run() { + try { + eatOutStreams(process, result); + } + catch (Exception e) { + if (result.isNull()) { + synchronized (result) { + result.notifyAll(); + } + } + } + } + }; + final Thread thread = new Thread(target, "Process Streams Reader"); + thread.setDaemon(true); + thread.start(); + synchronized (result) { + if (result.isNull()) { + result.wait(); + } + } + if (result.isNull()) throw new RuntimeException(); + else return Pair.create((MavenFacade)LocateRegistry.getRegistry(result.get().first).lookup(result.get().second), process); + } + + private static void eatOutStreams(Process process, Ref> result) throws Exception { + final InputStream stderr = process.getErrorStream(); + final InputStream stdout = process.getInputStream(); + final Reader errReader = new InputStreamReader(stderr); + final Reader outReader = new InputStreamReader(stdout); + final StringBuilder err = new StringBuilder(); + final StringBuilder out = new StringBuilder(); + final CharBuffer buffer = CharBuffer.allocate(1024); + int curOutIndex = 0; + + while (true) { + while (stderr.available() > 0) { + final int count = errReader.read(buffer); + err.append(buffer.array(), 0, count); + } + while (stdout.available() > 0) { + final int count = outReader.read(buffer); + out.append(buffer.array(), 0, count); + } + if (err.length() > 0) { + if (result.isNull()) { + break; + } + System.out.println(err); + err.setLength(0); + } + if (out.length() > 0) { + int nlIndex; + while ((nlIndex = out.indexOf("\n", curOutIndex)) >= 0) { + final String text = out.substring(curOutIndex, nlIndex); + curOutIndex = nlIndex + 1; + if (text.startsWith(PORT_ID_PREFIX)) { + final String pair = text.substring(PORT_ID_PREFIX.length()).trim(); + final int idx = pair.indexOf("/"); + final int port = Integer.parseInt(pair.substring(0, idx)); + final String name = pair.substring(idx + 1); + System.out.println("Connecting to: localhost:" + port + ". Looking up: " + name); + synchronized (result) { + result.set(Pair.create(port, name)); + result.notifyAll(); + } + } + } + curOutIndex = 0; + out.setLength(0); + } + Thread.sleep(1000L); + } + System.out.println("Destroying process"); + process.destroy(); + if (result.isNull()) { + synchronized (result) { + result.notifyAll(); + } + } + } + + public static void main(String[] args) throws Exception { + final String systemPath; + final ClassLoader loader = MavenFacadeLocator.class.getClassLoader(); + if (loader instanceof URLClassLoader) { + final URL[] urls = ((URLClassLoader)loader).getURLs(); + final StringBuilder sb = new StringBuilder(); + for (URL url : urls) { + if (sb.length() > 0) sb.append(File.pathSeparator); + sb.append(url.getFile().replace('/', File.separatorChar)); + } + systemPath = sb.toString(); + } + else { + systemPath = System.getProperty("java.class.path"); + } + + final String debug1 = "-Xdebug"; + final String debug2 = "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5009"; + final Pair pair = + acquireFacade(new String[]{"java", "-cp", systemPath, debug1, debug2, RemoteMavenServer.class.getName()}, null, null); + final MavenFacade facade = pair.first; + final MavenFacade.MavenFacadeSettings settings = new MavenFacade.MavenFacadeSettings(); + settings.getNexusUrls().add("http://repository.sonatype.org/service/local/"); + facade.setMavenSettings(settings); + final String lookup = args.length > 0 ? args[0] : "hibernate"; + System.out.println("Looking up: "+lookup); + final List result = facade.findArtifacts(createTemplate(lookup)); + int i=1; + for (ArtifactType type : result) { + System.out.println((++i)+". "+type.getGroupId()+":"+type.getArtifactId()+":"+type.getVersion()); + } + pair.second.destroy(); + System.exit(0); + } + + private static ArtifactType createTemplate(String coord) { + final ArtifactType template = new ArtifactType(); + final String[] parts = coord.split(":"); + template.setGroupId(parts.length > 0 ? parts[0] : null); + template.setArtifactId(parts.length > 1 ? parts[1] : null); + template.setVersion(parts.length > 2 ? parts[2] : null); + return template; + } + +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/RemoteMavenServer.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/RemoteMavenServer.java new file mode 100644 index 000000000000..bbb4223cdb72 --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/RemoteMavenServer.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2010 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.idea.maven.facade.remote; + +import org.jetbrains.idea.maven.facade.remote.impl.MavenFacadeImpl; + +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.ExportException; +import java.rmi.server.UnicastRemoteObject; +import java.util.Random; + +/** + * @author Gregory.Shrago + */ +public class RemoteMavenServer { + public static void main(String[] args) throws Exception { + Registry registry; + int port = 0; + for (Random random = new Random(); ;) { + port = random.nextInt(0xffff); + if (port < 4000) continue; + try { + registry = LocateRegistry.createRegistry(port); + break; + } + catch (ExportException ex) { + // try next port + } + } + try { + final MavenFacade mavenFacade = new MavenFacadeImpl(); + final MavenFacade stub = (MavenFacade)UnicastRemoteObject.exportObject(mavenFacade, 0); + final String name = "Maven" + Integer.toHexString(stub.hashCode()); + registry.bind(name, stub); + System.out.println("Port/ID:" + port + "/" + name); + final Object lock = new Object(); + synchronized (lock) { + lock.wait(); + } + } + catch (Throwable e) { + e.printStackTrace(); + System.exit(1); + } + } + +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/RemoteTransferListener.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/RemoteTransferListener.java new file mode 100644 index 000000000000..172c7a051476 --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/RemoteTransferListener.java @@ -0,0 +1,123 @@ +package org.jetbrains.idea.maven.facade.remote; + +import java.io.File; +import java.io.Serializable; +import java.rmi.Remote; +import java.rmi.RemoteException; + +/** + * @author Gregory.Shrago + */ +public interface RemoteTransferListener extends Remote { + void transferInitiated(TransferEvent transferEvent) throws RemoteException; + + void transferStarted(TransferEvent transferEvent) throws RemoteException; + + void transferProgress(TransferEvent transferEvent, int length) throws RemoteException; + + void transferCompleted(TransferEvent transferEvent) throws RemoteException; + + void transferError(TransferEvent transferEvent) throws RemoteException; + + void debug(String s) throws RemoteException; + + + class TransferEvent implements Serializable { + + public enum EventType { INITIATED, STARTED, COMPLETED, PROGRESS, ERROR } + public enum RequestType { PUT, GET } + + private final String myRepositoryUrl; + private final File myLocalFile; + private final EventType myEventType; + private final RequestType myRequestType; + private final Resource myResource; + private final Exception myException; + + public TransferEvent(File localFile, + EventType eventType, + RequestType requestType, + Resource resource, + Exception exception, + String repositoryUrl) { + myLocalFile = localFile; + myEventType = eventType; + myRequestType = requestType; + myResource = resource; + myException = exception; + myRepositoryUrl = repositoryUrl; + } + + public String getRepositoryUrl() { + return myRepositoryUrl; + } + + public File getLocalFile() { + return myLocalFile; + } + + public EventType getEventType() { + return myEventType; + } + + public RequestType getRequestType() { + return myRequestType; + } + + public Exception getException() { + return myException; + } + + public Resource getResource() { + return myResource; + } + } + + class Resource implements Serializable { + + private final String myResourceName; + private final long myResourceLastModified; + private final long myResourceContentLength; + + public Resource(String resourceName, long resourceLastModified, long resourceContentLength) { + myResourceName = resourceName; + myResourceLastModified = resourceLastModified; + myResourceContentLength = resourceContentLength; + } + + public String getResourceName() { + return myResourceName; + } + + public long getResourceLastModified() { + return myResourceLastModified; + } + + public long getResourceContentLength() { + return myResourceContentLength; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Resource resource = (Resource)o; + + if (myResourceContentLength != resource.myResourceContentLength) return false; + if (myResourceLastModified != resource.myResourceLastModified) return false; + if (!myResourceName.equals(resource.myResourceName)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myResourceName.hashCode(); + result = 31 * result + (int)(myResourceLastModified ^ (myResourceLastModified >>> 32)); + result = 31 * result + (int)(myResourceContentLength ^ (myResourceContentLength >>> 32)); + return result; + } + } + +} \ No newline at end of file diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/impl/MavenFacadeImpl.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/impl/MavenFacadeImpl.java new file mode 100644 index 000000000000..f52c4fee3270 --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/impl/MavenFacadeImpl.java @@ -0,0 +1,341 @@ +/* + * Copyright 2000-2010 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.idea.maven.facade.remote.impl; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.DefaultArtifact; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.manager.WagonManager; +import org.apache.maven.artifact.metadata.ArtifactMetadataSource; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.repository.DefaultArtifactRepository; +import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; +import org.apache.maven.artifact.resolver.*; +import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter; +import org.apache.maven.artifact.versioning.VersionRange; +import org.apache.maven.settings.MavenSettingsBuilder; +import org.apache.maven.settings.RuntimeInfo; +import org.apache.maven.settings.Settings; +import org.apache.maven.wagon.events.TransferEvent; +import org.apache.maven.wagon.events.TransferListener; +import org.codehaus.classworlds.ClassWorld; +import org.codehaus.plexus.DefaultPlexusContainer; +import org.codehaus.plexus.PlexusContainerException; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.jetbrains.idea.maven.facade.nexus.ArtifactType; +import org.jetbrains.idea.maven.facade.nexus.Endpoint; +import org.jetbrains.idea.maven.facade.nexus.SearchResults; +import org.jetbrains.idea.maven.facade.remote.MavenFacade; +import org.jetbrains.idea.maven.facade.remote.RemoteTransferListener; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.rmi.RemoteException; +import java.util.*; + +/** + * @author Gregory.Shrago + */ +public class MavenFacadeImpl extends RemoteImpl implements MavenFacade { + + private static final DefaultPlexusContainer ourContainer = initializeMaven(); + private MavenFacadeSettings mySettings; + + public static DefaultPlexusContainer initializeMaven() { + DefaultPlexusContainer container; + try { + container = new DefaultPlexusContainer(); + } + catch (RuntimeException e) { + String s = "Cannot initialize Maven. Please make sure that your IDEA installation is correct and has no old libraries."; + throw new RuntimeException(s, e); + } + + container.setClassWorld(new ClassWorld("plexus.core", Thread.currentThread().getContextClassLoader())); +// CustomLoggerManager loggerManager = new CustomLoggerManager(generalSettings.getLoggingLevel()); +// container.setLoggerManager(loggerManager); + + try { + container.initialize(); + container.start(); + } + catch (PlexusContainerException e) { + throw new RuntimeException(e); + } + +// System.setProperty("maven.home", "<...>"); +// System.setProperty(MavenSettingsBuilder.ALT_GLOBAL_SETTINGS_XML_LOCATION, "<..>"); + + Settings settings = null; + + try { + MavenSettingsBuilder builder = (MavenSettingsBuilder)container.lookup(MavenSettingsBuilder.ROLE); +// File userSettingsFile = generalSettings.getEffectiveUserSettingsIoFile(); +// if (userSettingsFile != null && userSettingsFile.exists() && !userSettingsFile.isDirectory()) { +// settings = builder.buildSettings(userSettingsFile, false); +// } + if (settings == null) { + settings = builder.buildSettings(); + } + } + catch (ComponentLookupException e) { + e.printStackTrace(); + } + catch (IOException e) { + e.printStackTrace(); + } + catch (XmlPullParserException e) { + e.printStackTrace(); + } + + if (settings == null) { + settings = new Settings(); + } + +// settings.setLocalRepository("<...>"); + + settings.setOffline(false); + settings.setInteractiveMode(false); + settings.setUsePluginRegistry(false); + + RuntimeInfo runtimeInfo = new RuntimeInfo(settings); +// runtimeInfo.setPluginUpdateOverride(generalSettings.getPluginUpdatePolicy() == MavenExecutionOptions.PluginUpdatePolicy.UPDATE); + settings.setRuntimeInfo(runtimeInfo); + + return container; + + } + + public List findArtifacts(ArtifactType template) throws RemoteException { + final HashMap result = new HashMap(); + for (String url : mySettings.getNexusUrls()) { + try { + final SearchResults results = new Endpoint.DataIndex(url) + .getArtifactlistAsSearchResults(null, template.getGroupId(), template.getArtifactId(), template.getVersion(), + template.getClassifier()); + for (ArtifactType artifact : results.getData().getArtifact()) { + result.put(artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion(), artifact); + } + } + catch (Exception e) { + e.printStackTrace(); + } + } + return new ArrayList(result.values()); + } + + public Map> resolveDependencies(List artifacts) throws RemoteException { + try { + return resolveDependenciesInner(artifacts); + } + catch (Exception e) { + handleException(e); + throw new AssertionError(); + } + } + + public void setTransferListener(final RemoteTransferListener listener) throws RemoteException { + try { + final WagonManager wagonManager = (WagonManager)ourContainer.lookup(WagonManager.ROLE); + if (listener == null) { + wagonManager.setDownloadMonitor(null); + return; + } + wagonManager.setDownloadMonitor(new TransferListener() { + public void transferInitiated(TransferEvent transferEvent) { + try { + listener.transferInitiated(convert(transferEvent)); + } + catch (RemoteException ignored) { } + } + + public void transferStarted(TransferEvent transferEvent) { + try { + listener.transferStarted(convert(transferEvent)); + } + catch (RemoteException ignored) { + } + } + + public void transferProgress(TransferEvent transferEvent, byte[] bytes, int i) { + try { + listener.transferProgress(convert(transferEvent), i); + } + catch (RemoteException ignored) { + } + } + + public void transferCompleted(TransferEvent transferEvent) { + try { + listener.transferCompleted(convert(transferEvent)); + } + catch (RemoteException ignored) { + } + } + + public void transferError(TransferEvent transferEvent) { + try { + listener.transferError(convert(transferEvent)); + } + catch (RemoteException ignored) { + } + } + + public void debug(String s) { + try { + listener.debug(s); + } + catch (RemoteException ignored) { + } + } + }); + } + catch (Exception e) { + handleException(e); + throw new AssertionError(); + } + } + + public void setMavenSettings(MavenFacadeSettings settings) throws RemoteException { + mySettings = settings; + } + + private static RemoteTransferListener.TransferEvent convert(TransferEvent transferEvent) { + final RemoteTransferListener.TransferEvent.EventType et; + switch (transferEvent.getEventType()) { + case TransferEvent.TRANSFER_INITIATED: et = RemoteTransferListener.TransferEvent.EventType.INITIATED; break; + case TransferEvent.TRANSFER_STARTED: et = RemoteTransferListener.TransferEvent.EventType.STARTED; break; + case TransferEvent.TRANSFER_PROGRESS: et = RemoteTransferListener.TransferEvent.EventType.PROGRESS; break; + case TransferEvent.TRANSFER_COMPLETED: et = RemoteTransferListener.TransferEvent.EventType.COMPLETED; break; + case TransferEvent.TRANSFER_ERROR: et = RemoteTransferListener.TransferEvent.EventType.ERROR; break; + default: throw new AssertionError(transferEvent.getEventType()); + } + final RemoteTransferListener.TransferEvent.RequestType reqType = transferEvent.getRequestType() == TransferEvent.REQUEST_GET + ? RemoteTransferListener.TransferEvent.RequestType.GET + : RemoteTransferListener.TransferEvent.RequestType.PUT; + final RemoteTransferListener.Resource resource = new RemoteTransferListener.Resource(transferEvent.getResource().getName(), + transferEvent.getResource().getLastModified(), + transferEvent.getResource().getContentLength()); + return new RemoteTransferListener.TransferEvent(transferEvent.getLocalFile(), et, reqType, resource, transferEvent.getException(), transferEvent.getWagon().getRepository().getUrl()); + } + + + private Map> resolveDependenciesInner(List artifactsToResolve) throws Exception { + final ArtifactResolver resolver = (ArtifactResolver)ourContainer.lookup(ArtifactResolver.ROLE); + final ArtifactFactory artifactFactory = (ArtifactFactory)ourContainer.lookup(ArtifactFactory.ROLE); + final ArtifactMetadataSource metadataSource = (ArtifactMetadataSource)ourContainer.lookup(ArtifactMetadataSource.ROLE); + + final ArtifactRepository localRepo = getRepository(mySettings.getLocalRepository()); + final List remoteRepos = new ArrayList(); + for (Repository repository : mySettings.getRemoteRepositories()) { + remoteRepos.add(getRepository(repository)); + } + + + final Artifact project = artifactFactory.createBuildArtifact("local", "project", "1.0", "pom"); + final Set toResolve = new HashSet(); + for (ArtifactType template : artifactsToResolve) { + final Artifact artifact = artifactFactory.createDependencyArtifact( + template.getGroupId(), + template.getArtifactId(), + template.getVersion() == null? null :VersionRange.createFromVersion(template.getVersion()), + template.getPackaging(), + null, + "runtime"); + toResolve.add(artifact); + } + +// resolver.resolve(artifact, remoteRepos, localRepo); +// final List list = (List)metadataSource.retrieveAvailableVersions(artifact, localRepo, remoteRepos); +// for (ArtifactVersion o : list) { +// System.out.println("avail version: " + o); +// } + final Map> resultMap = new HashMap>(); + for (Artifact artifact : toResolve) { + try { + final ArtifactResolutionResult result = resolver.resolveTransitively( + Collections.singleton(artifact), project, Collections.EMPTY_MAP, localRepo, remoteRepos, + metadataSource, new ScopeArtifactFilter(DefaultArtifact.SCOPE_RUNTIME)); + resultMap.put(getCoordinate(artifact), toArtifactTypeList(result.getArtifacts())); + } + catch (MultipleArtifactsNotFoundException e) { + resultMap.put(getCoordinate(artifact), toArtifactTypeList(e.getResolvedArtifacts())); + //System.out.println("Missing: -------------------"); + //toArtifactTypeList(e.getMissingArtifacts()); + } + catch (ArtifactResolutionException e) { + //throw e; + } + catch (ArtifactNotFoundException e) { + //throw e; + //System.out.println("Missing: -------------------"); + //toArtifactTypeList(Collections.singletonList(e.getArtifact())); + } + } + return resultMap; + } + + private static ArtifactRepository getRepository(Repository r) throws ComponentLookupException { + final ArtifactRepositoryLayout repoLayout = (ArtifactRepositoryLayout)ourContainer.lookup(ArtifactRepositoryLayout.ROLE, r.getLayout()); + return new DefaultArtifactRepository(r.getId(), r.getUrl(), repoLayout); + } + + private static Map> toArtifactTypeMap(Collection toResolve, Collection resolvedArtifacts) { + final Map> result = new HashMap>(); + final Map idMap = new HashMap(); + for (Artifact artifact : toResolve) { + idMap.put(artifact.getId(), getCoordinate(artifact)); + result.put(getCoordinate(artifact), new ArrayList()); + } + for (Artifact artifact : resolvedArtifacts) { + List list = null; + for (String s : artifact.getDependencyTrail()) { + list = result.get(idMap.get(s)); + if (list != null) { + list.add(toArtifactType(artifact)); + break; + } + } + if (list == null) { + throw new AssertionError(getCoordinate(artifact)); + } + } + return result; + } + + private static String getCoordinate(Artifact artifact) { + return artifact.getGroupId()+":"+artifact.getArtifactId()+":"+artifact.getVersion(); + } + + private static List toArtifactTypeList(Collection artifacts) throws MalformedURLException { + final ArrayList result = new ArrayList(artifacts.size()); + for (Artifact artifact : artifacts) { + result.add(toArtifactType(artifact)); + } + return result; + } + + private static ArtifactType toArtifactType(Artifact artifact) { + final ArtifactType type = new ArtifactType(); + type.setGroupId(artifact.getGroupId()); + type.setArtifactId(artifact.getArtifactId()); + type.setVersion(artifact.getVersion()); + type.setClassifier(artifact.getClassifier()); + type.setResourceUri(artifact.getFile().toURI().toASCIIString()); + return type; + } +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/impl/RemoteImpl.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/impl/RemoteImpl.java new file mode 100644 index 000000000000..4f5b944710cb --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/impl/RemoteImpl.java @@ -0,0 +1,95 @@ +package org.jetbrains.idea.maven.facade.remote.impl; + +import com.intellij.util.containers.ContainerUtil; + +import java.lang.ref.WeakReference; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.server.UnicastRemoteObject; +import java.rmi.server.Unreferenced; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Gregory.Shrago + */ +public class RemoteImpl implements Remote, Unreferenced { + private final Map myChildren = new ConcurrentHashMap(); + private final WeakReference myWeakRef; + private RemoteImpl myParent; + + public RemoteImpl() { + myWeakRef = new WeakReference(this); + } + + public WeakReference getWeakRef() { + return myWeakRef; + } + + protected T export(final T child) throws RemoteException { + if (child == null) return null; + final T result = (T)UnicastRemoteObject.exportObject(child, 0); + myChildren.put((RemoteImpl)child, result); + ((RemoteImpl)child).myParent = this; + return result; + } + + protected T export2(final T child) throws RemoteException { + return export(child); + } + + public void unexportChildren() throws RemoteException { + final ArrayList childrenRefs = new ArrayList(myChildren.keySet()); + myChildren.clear(); + for (RemoteImpl child : childrenRefs) { + child.unreferenced(); + } + } + + protected void unexportChildren(Collection> children) throws RemoteException { + if (children.isEmpty()) return; + final ArrayList list = new ArrayList(children.size()); + for (WeakReference child : children) { + ContainerUtil.addIfNotNull(child.get(), list); + } + myChildren.keySet().removeAll(list); + for (RemoteImpl child : list) { + child.unreferenced(); + } + } + + protected static void handleException(Exception e) { + Throwable cause = e; + while (cause.getCause() != null) { + cause = cause.getCause(); + } + if (!cause.getClass().getName().startsWith("java")) { + final Throwable replaceWith = new RuntimeException(cause.toString()); + replaceWith.setStackTrace(cause.getStackTrace()); + cause = replaceWith; + } + throw cause instanceof RuntimeException ? (RuntimeException)cause : new RuntimeException(cause); + } + + public Object wrapIfNeeded(Object o) throws RemoteException { + if (o == null) return o; + if (o.getClass().getClassLoader() == null || + o.getClass().getName().startsWith("com.intellij")) return o; + return o.toString(); + } + + public void unreferenced() { + if (myParent != null) { + myParent.myChildren.remove(this); + myParent = null; + try { + unexportChildren(); + UnicastRemoteObject.unexportObject(this, false); + } + catch (RemoteException e) { + } + } + } +} diff --git a/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/impl/RemoteTransferListenerImpl.java b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/impl/RemoteTransferListenerImpl.java new file mode 100644 index 000000000000..d418cc5ed90d --- /dev/null +++ b/plugins/maven/facade/org/jetbrains/idea/maven/facade/remote/impl/RemoteTransferListenerImpl.java @@ -0,0 +1,28 @@ +package org.jetbrains.idea.maven.facade.remote.impl; + +import org.jetbrains.idea.maven.facade.remote.RemoteTransferListener; + +/** + * @author Gregory.Shrago + */ +public class RemoteTransferListenerImpl extends RemoteImpl implements RemoteTransferListener { + + public void transferInitiated(TransferEvent transferEvent) { + } + + public void transferStarted(TransferEvent transferEvent) { + } + + public void transferProgress(TransferEvent transferEvent, int length) { + } + + public void transferCompleted(TransferEvent transferEvent) { + } + + public void transferError(TransferEvent transferEvent) { + } + + public void debug(String s) { + } + +} diff --git a/plugins/maven/lib/activation-1.1.jar b/plugins/maven/lib/activation-1.1.jar new file mode 100644 index 000000000000..66d290ee4554 Binary files /dev/null and b/plugins/maven/lib/activation-1.1.jar differ diff --git a/plugins/maven/lib/jaxb-api-2.1.jar b/plugins/maven/lib/jaxb-api-2.1.jar new file mode 100644 index 000000000000..2b5dc7e398c9 Binary files /dev/null and b/plugins/maven/lib/jaxb-api-2.1.jar differ diff --git a/plugins/maven/lib/jaxb-impl-2.1.10.jar b/plugins/maven/lib/jaxb-impl-2.1.10.jar new file mode 100644 index 000000000000..37ad4cc1fcf5 Binary files /dev/null and b/plugins/maven/lib/jaxb-impl-2.1.10.jar differ diff --git a/plugins/maven/lib/wadl-core.jar b/plugins/maven/lib/wadl-core.jar new file mode 100644 index 000000000000..fd9b0de32aee Binary files /dev/null and b/plugins/maven/lib/wadl-core.jar differ diff --git a/plugins/maven/maven-facade.iml b/plugins/maven/maven-facade.iml new file mode 100644 index 000000000000..296802213a70 --- /dev/null +++ b/plugins/maven/maven-facade.iml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/maven/maven.iml b/plugins/maven/maven.iml index 096f1954a099..23e9cf02df7f 100644 --- a/plugins/maven/maven.iml +++ b/plugins/maven/maven.iml @@ -121,15 +121,12 @@ + - - - - diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/refactorings/introduce/IntroducePropertyAction.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/refactorings/introduce/IntroducePropertyAction.java index 83f9819b179d..07a7444ec728 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/refactorings/introduce/IntroducePropertyAction.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/refactorings/introduce/IntroducePropertyAction.java @@ -26,8 +26,9 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.*; import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.actions.BaseRefactoringAction; -import com.intellij.usageView.UsageInfo; +import com.intellij.usageView.*; import com.intellij.usages.*; +import com.intellij.usages.UsageViewManager; import com.intellij.util.Processor; import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.NotNull; @@ -164,6 +165,8 @@ public class IntroducePropertyAction extends BaseRefactoringAction { UsageViewManager manager = UsageViewManager.getInstance(project); if (manager == null) return; + assureFindToolWindowRegistered(project); + FindManager findManager = FindManager.getInstance(project); FindModel findModel = createFindModel(findManager, selectedString, replaceWith); @@ -180,6 +183,12 @@ public class IntroducePropertyAction extends BaseRefactoringAction { } + //IDEA-54113 + private static void assureFindToolWindowRegistered(@NotNull Project project) { + com.intellij.usageView.UsageViewManager uvm = com.intellij.usageView.UsageViewManager.getInstance(project); + + } + private static FindModel createFindModel(FindManager findManager, String selectedString, String replaceWith) { FindModel findModel = (FindModel)findManager.getFindInProjectModel().clone(); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java index f34cb4e8d9f3..83094fc6cc7f 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java @@ -831,7 +831,7 @@ public class MavenProjectsManager extends SimpleProjectComponent MavenUtil.runWhenInitialized(myProject, wrapper.get()); } - private void schedulePostImportTasts(List postTasks) { + private void schedulePostImportTasks(List postTasks) { for (MavenProjectsProcessorTask each : postTasks) { myPostProcessor.scheduleTask(each); } @@ -941,7 +941,7 @@ public class MavenProjectsManager extends SimpleProjectComponent VirtualFileManager.getInstance().refresh(isNormalProject()); - schedulePostImportTasts(postTasks.get()); + schedulePostImportTasks(postTasks.get()); // do not block user too often myImportingQueue.restartTimer(); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenAttachSourcesProvider.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenAttachSourcesProvider.java index 54269460b2f5..49467a4918ba 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenAttachSourcesProvider.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenAttachSourcesProvider.java @@ -20,9 +20,9 @@ import com.intellij.notification.Notification; import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.LibraryOrderEntry; import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.AsyncResult; import com.intellij.psi.PsiFile; @@ -31,15 +31,13 @@ import org.jetbrains.idea.maven.importing.MavenRootModelAdapter; import org.jetbrains.idea.maven.project.*; import javax.swing.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; +import java.util.*; public class MavenAttachSourcesProvider implements AttachSourcesProvider { - public Collection getActions(final Library library, final PsiFile psiFile) { + public Collection getActions(final List orderEntries, final PsiFile psiFile) { Collection projects = getMavenProjects(psiFile); if (projects.isEmpty()) return Collections.emptyList(); - if (findArtifacts(projects, library).isEmpty()) return Collections.emptyList(); + if (findArtifacts(projects, orderEntries).isEmpty()) return Collections.emptyList(); return Collections.singleton(new AttachSourcesAction() { public String getName() { @@ -50,14 +48,14 @@ public class MavenAttachSourcesProvider implements AttachSourcesProvider { return ProjectBundle.message("maven.action.download.sources.busy.text"); } - public ActionCallback perform() { + public ActionCallback perform(List orderEntries) { // may have been changed by this time... Collection mavenProjects = getMavenProjects(psiFile); if (mavenProjects.isEmpty()) return new ActionCallback.Rejected(); MavenProjectsManager manager = MavenProjectsManager.getInstance(psiFile.getProject()); - Collection artifacts = findArtifacts(mavenProjects, library); + Collection artifacts = findArtifacts(mavenProjects, orderEntries); if (artifacts.isEmpty()) return new ActionCallback.Rejected(); final AsyncResult result = new AsyncResult(); @@ -105,16 +103,18 @@ public class MavenAttachSourcesProvider implements AttachSourcesProvider { }); } - private Collection findArtifacts(Collection mavenProjects, Library library) { + private static Collection findArtifacts(Collection mavenProjects, List orderEntries) { Collection artifacts = new THashSet(); for (MavenProject each : mavenProjects) { - final MavenArtifact artifact = MavenRootModelAdapter.findArtifact(each, library); - if (artifact != null) artifacts.add(artifact); + for (LibraryOrderEntry entry : orderEntries) { + final MavenArtifact artifact = MavenRootModelAdapter.findArtifact(each, entry.getLibrary()); + if (artifact != null) artifacts.add(artifact); + } } return artifacts; } - private Collection getMavenProjects(PsiFile psiFile) { + private static Collection getMavenProjects(PsiFile psiFile) { Project project = psiFile.getProject(); Collection result = new ArrayList(); for (OrderEntry each : ProjectRootManager.getInstance(project).getFileIndex().getOrderEntriesForFile(psiFile.getVirtualFile())) { diff --git a/plugins/maven/src/main/resources/META-INF/gwt-support.xml b/plugins/maven/src/main/resources/META-INF/gwt-support.xml deleted file mode 100644 index 5ce477b335f6..000000000000 --- a/plugins/maven/src/main/resources/META-INF/gwt-support.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/plugins/maven/src/main/resources/META-INF/jee-support.xml b/plugins/maven/src/main/resources/META-INF/jee-support.xml deleted file mode 100644 index 8eda561b4bc5..000000000000 --- a/plugins/maven/src/main/resources/META-INF/jee-support.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index 5a4943bf949c..9dbc9160afb8 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -11,10 +11,7 @@ com.intellij.properties - org.intellij.groovy - com.intellij.uml - com.intellij.javaee - com.intellij.gwt + org.intellij.groovy diff --git a/plugins/maven/src/main/resources/META-INF/uml-support.xml b/plugins/maven/src/main/resources/META-INF/uml-support.xml deleted file mode 100644 index 0da394308b75..000000000000 --- a/plugins/maven/src/main/resources/META-INF/uml-support.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/plugins/properties/src/com/intellij/codeInspection/duplicatePropertyInspection/DuplicatePropertyInspection.java b/plugins/properties/src/com/intellij/codeInspection/duplicatePropertyInspection/DuplicatePropertyInspection.java index 20ce5e9ce170..e588c5261c1a 100644 --- a/plugins/properties/src/com/intellij/codeInspection/duplicatePropertyInspection/DuplicatePropertyInspection.java +++ b/plugins/properties/src/com/intellij/codeInspection/duplicatePropertyInspection/DuplicatePropertyInspection.java @@ -173,7 +173,7 @@ public class DuplicatePropertyInspection extends DescriptorProviderInspection { final ProgressIndicator progress = ProgressWrapper.wrap(original); ProgressManager.getInstance().runProcess(new Runnable() { public void run() { - JobUtil.invokeConcurrentlyUnderMyProgress(properties, new Processor() { + if (!JobUtil.invokeConcurrentlyUnderMyProgress(properties, new Processor() { public boolean process(final Property property) { if (original != null) { if (original.isCanceled()) return false; @@ -183,7 +183,7 @@ public class DuplicatePropertyInspection extends DescriptorProviderInspection { processTextUsages(processedKeyToFiles, property.getUnescapedKey(), processedValueToFiles, searchHelper, scope); return true; } - }, "Searching properties usages"); + }, "Searching properties usages")) throw new ProcessCanceledException(); List problemDescriptors = new ArrayList(); Map> keyToDifferentValues = new HashMap>(); diff --git a/plugins/properties/src/com/intellij/lang/properties/UnusedPropertyInspection.java b/plugins/properties/src/com/intellij/lang/properties/UnusedPropertyInspection.java index 1258a741049b..5d7e54f57e1a 100644 --- a/plugins/properties/src/com/intellij/lang/properties/UnusedPropertyInspection.java +++ b/plugins/properties/src/com/intellij/lang/properties/UnusedPropertyInspection.java @@ -24,6 +24,7 @@ import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.lang.properties.psi.Property; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.psi.PsiElement; @@ -61,7 +62,7 @@ public class UnusedPropertyInspection extends PropertySuppressableInspectionBase final GlobalSearchScope searchScope = GlobalSearchScope.moduleWithDependentsScope(module); final ProgressIndicator original = ProgressManager.getInstance().getProgressIndicator(); - JobUtil.invokeConcurrentlyUnderMyProgress(properties, new Processor() { + if (!JobUtil.invokeConcurrentlyUnderMyProgress(properties, new Processor() { public boolean process(final Property property) { if (original != null) { if (original.isCanceled()) return false; @@ -93,7 +94,7 @@ public class UnusedPropertyInspection extends PropertySuppressableInspectionBase return true; } - }, "Searching properties usages"); + }, "Searching properties usages")) throw new ProcessCanceledException(); synchronized (descriptors) { return descriptors.toArray(new ProblemDescriptor[descriptors.size()]); diff --git a/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index 7f8c767be64b..fb9e26ab30dc 100644 --- a/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -108,6 +108,5 @@ utf stylesheet charset vertices -commandline -cmdline -multi \ No newline at end of file +println +encoded diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java index 70fed049fd9a..9f0c3d7b6db4 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java @@ -41,7 +41,8 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.LanguageLevelUtil; import com.intellij.openapi.module.Module; -import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; +import com.intellij.openapi.progress.impl.ProgressManagerImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.ex.JavaSdkUtil; @@ -59,7 +60,10 @@ import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.pom.java.LanguageLevel; import com.intellij.util.PathUtil; import com.intellij.util.net.NetUtils; -import com.theoryinpractice.testng.model.*; +import com.theoryinpractice.testng.model.IDEARemoteTestRunnerClient; +import com.theoryinpractice.testng.model.TestData; +import com.theoryinpractice.testng.model.TestNGRemoteListener; +import com.theoryinpractice.testng.model.TestType; import com.theoryinpractice.testng.ui.TestNGConsoleView; import com.theoryinpractice.testng.ui.TestNGResults; import com.theoryinpractice.testng.ui.actions.RerunFailedTestsAction; @@ -72,9 +76,11 @@ import org.testng.annotations.AfterClass; import org.testng.remote.strprotocol.MessageHelper; import javax.swing.*; -import java.io.*; +import java.io.File; +import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; +import java.net.Socket; import java.net.UnknownHostException; public class TestNGRunnableState extends JavaCommandLineState { @@ -86,6 +92,7 @@ public class TestNGRunnableState extends JavaCommandLineState { private int port; private String debugPort; private File myTempFile; + private BackgroundableProcessIndicator mySearchForTestIndicator; public TestNGRunnableState(ExecutionEnvironment environment, TestNGConfiguration config) { super(environment); @@ -114,9 +121,18 @@ public class TestNGRunnableState extends JavaCommandLineState { @Override public ExecutionResult execute(@NotNull final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException { + OSProcessHandler processHandler = null; + try { + processHandler = startProcess(); + } + catch (ExecutionException e) { + if (mySearchForTestIndicator != null && !mySearchForTestIndicator.isCanceled()) { + mySearchForTestIndicator.cancel(); + } + throw e; + } final TestNGConsoleView console = new TestNGConsoleView(config, runnerSettings, myConfigurationPerRunnerSettings); console.initUI(); - OSProcessHandler processHandler = startProcess(); for (RunConfigurationExtension ext : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) { ext.handleStartProcess(config, processHandler); } @@ -306,7 +322,22 @@ public class TestNGRunnableState extends JavaCommandLineState { myTempFile = File.createTempFile("idea_testng", ".tmp"); myTempFile.deleteOnExit(); javaParameters.getProgramParametersList().add("-temp", myTempFile.getAbsolutePath()); - ProgressManager.getInstance().run(new SearchingForTestsTask(serverSocket, is15, config, myTempFile)); + final SearchingForTestsTask task = new SearchingForTestsTask(serverSocket, is15, config, myTempFile); + mySearchForTestIndicator = new BackgroundableProcessIndicator(task) { + @Override + public void cancel() { + try {//ensure that serverSocket.accept was interrupted + if (!serverSocket.isClosed()) { + new Socket(InetAddress.getLocalHost(), serverSocket.getLocalPort()); + } + } + catch (Throwable e) { + LOG.info(e); + } + super.cancel(); + } + }; + ProgressManagerImpl.runProcessWithProgressAsynchronously(task, mySearchForTestIndicator); } catch (IOException e) { LOG.error(e); diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomManagerImpl.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomManagerImpl.java index 82fab83bb460..9d6f20c1c2d0 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomManagerImpl.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomManagerImpl.java @@ -168,7 +168,7 @@ public final class DomManagerImpl extends DomManager { return; } - if (StdFileTypes.XML.equals(file.getFileType())) { + if (file.isValid() && StdFileTypes.XML.equals(file.getFileType())) { final PsiFile psiFile = psiManager.findFile(file); if (psiFile instanceof XmlFile) { myDeletedFiles.add((XmlFile)psiFile); diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/FilterToken.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/FilterToken.java new file mode 100644 index 000000000000..4a79f392a302 --- /dev/null +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/FilterToken.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.template.zencoding; + +/** + * @author Eugene.Kudelevsky + */ +public class FilterToken extends Token { + private final String mySuffix; + + public FilterToken(String suffix) { + mySuffix = suffix; + } + + public String getSuffix() { + return mySuffix; + } +} diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/NumberToken.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/NumberToken.java index 4adf4f763c59..d101c8f4325f 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/NumberToken.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/NumberToken.java @@ -19,9 +19,13 @@ package com.intellij.codeInsight.template.zencoding; * @author Eugene.Kudelevsky */ class NumberToken extends Token { - final int myNumber; + private final int myNumber; NumberToken(int number) { myNumber = number; } + + public int getNumber() { + return myNumber; + } } diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/OperationToken.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/OperationToken.java index 63bb2d343e6c..b33e164eee8e 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/OperationToken.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/OperationToken.java @@ -19,9 +19,13 @@ package com.intellij.codeInsight.template.zencoding; * @author Eugene.Kudelevsky */ class OperationToken extends Token { - final char mySign; + private final char mySign; OperationToken(char sign) { mySign = sign; } + + public char getSign() { + return mySign; + } } diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/TemplateToken.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/TemplateToken.java index bb9b2f96b0f6..1a0f490fbe64 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/TemplateToken.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/TemplateToken.java @@ -16,20 +16,27 @@ package com.intellij.codeInsight.template.zencoding; import com.intellij.codeInsight.template.impl.TemplateImpl; -import com.intellij.openapi.util.Pair; - -import java.util.List; /** * @author Eugene.Kudelevsky */ -class TemplateToken extends Token { - final String myKey; - final List> myAttribute2Value; - TemplateImpl myTemplate; +public class TemplateToken extends Token { + private final String myKey; + private TemplateImpl myTemplate; - TemplateToken(String key, List> attribute2value) { + public TemplateToken(String key) { myKey = key; - myAttribute2Value = attribute2value; + } + + public String getKey() { + return myKey; + } + + public void setTemplate(TemplateImpl template) { + myTemplate = template; + } + + public TemplateImpl getTemplate() { + return myTemplate; } } diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlTemplateToken.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlTemplateToken.java new file mode 100644 index 000000000000..ad0bfe583d28 --- /dev/null +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlTemplateToken.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.template.zencoding; + +import com.intellij.openapi.util.Pair; +import com.intellij.psi.xml.XmlTag; + +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +public class XmlTemplateToken extends TemplateToken { + private final List> myAttribute2Value; + private XmlTag myTag; + + public XmlTemplateToken(String key, List> attribute2value) { + super(key); + myAttribute2Value = attribute2value; + } + + public List> getAttribute2Value() { + return myAttribute2Value; + } + + public XmlTag getTag() { + return myTag; + } + + public void setTag(XmlTag tag) { + myTag = tag; + } +} diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingFilter.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingFilter.java new file mode 100644 index 000000000000..6a54754ad259 --- /dev/null +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingFilter.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.template.zencoding; + +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiElement; +import com.intellij.psi.xml.XmlTag; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +public abstract class XmlZenCodingFilter implements ZenCodingFilter { + @NotNull + public String toString(@NotNull TemplateToken token, @NotNull PsiElement context) { + if (!(token instanceof XmlTemplateToken)) { + throw new IllegalArgumentException(); + } + return toString(((XmlTemplateToken)token).getTag(), context); + } + + protected abstract String toString(@NotNull XmlTag tag, @NotNull PsiElement context); + + @NotNull + public abstract String buildAttributesString(@NotNull List> attribute2value, int numberInIteration); + + public abstract boolean isMyContext(@NotNull PsiElement context); +} diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingFilterImpl.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingFilterImpl.java new file mode 100644 index 000000000000..7c39e883deab --- /dev/null +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingFilterImpl.java @@ -0,0 +1,122 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.template.zencoding; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.xml.XmlChildRole; +import com.intellij.psi.xml.XmlTag; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +public class XmlZenCodingFilterImpl extends XmlZenCodingFilter { + @NotNull + public String toString(@NotNull XmlTag tag, @NotNull PsiElement context) { + FileType fileType = context.getContainingFile().getFileType(); + if (XmlZenCodingTemplate.isTrueXml(fileType)) { + closeUnclosingTags(tag); + } + return tag.getContainingFile().getText(); + } + + @NotNull + public String buildAttributesString(@NotNull List> attribute2value, int numberInIteration) { + StringBuilder result = new StringBuilder(); + for (Iterator> it = attribute2value.iterator(); it.hasNext();) { + Pair pair = it.next(); + String name = pair.first; + String value = ZenCodingUtil.getValue(pair, numberInIteration); + result.append(getAttributeString(name, value)); + if (it.hasNext()) { + result.append(' '); + } + } + return result.toString(); + } + + public boolean isMyContext(@NotNull PsiElement context) { + return true; + } + + public String getSuffix() { + return null; + } + + public boolean isDefaultFilter() { + return true; + } + + private static String getAttributeString(String name, String value) { + return name + "=\"" + value + '"'; + } + + @SuppressWarnings({"ConstantConditions"}) + private static void closeUnclosingTags(@NotNull XmlTag root) { + final List> tagToClose = new ArrayList>(); + Project project = root.getProject(); + final SmartPointerManager pointerManager = SmartPointerManager.getInstance(project); + root.accept(new XmlRecursiveElementVisitor() { + @Override + public void visitXmlTag(final XmlTag tag) { + if (!isTagClosed(tag)) { + tagToClose.add(pointerManager.createLazyPointer(tag)); + } + } + }); + PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); + for (final SmartPsiElementPointer pointer : tagToClose) { + final XmlTag tag = pointer.getElement(); + if (tag != null) { + final ASTNode child = XmlChildRole.START_TAG_END_FINDER.findChild(tag.getNode()); + if (child != null) { + final int offset = child.getTextRange().getStartOffset(); + VirtualFile file = tag.getContainingFile().getVirtualFile(); + if (file != null) { + final Document document = FileDocumentManager.getInstance().getDocument(file); + documentManager.doPostponedOperationsAndUnblockDocument(document); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + document.replaceString(offset, tag.getTextRange().getEndOffset(), "/>"); + } + }); + } + } + } + } + documentManager.commitAllDocuments(); + } + + private static boolean isTagClosed(@NotNull XmlTag tag) { + ASTNode node = tag.getNode(); + assert node != null; + final ASTNode emptyTagEnd = XmlChildRole.EMPTY_TAG_END_FINDER.findChild(node); + final ASTNode endTagEnd = XmlChildRole.CLOSING_TAG_START_FINDER.findChild(node); + return emptyTagEnd != null || endTagEnd != null; + } +} diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingInterpreter.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingInterpreter.java index 2f74ada15052..3600106a09cf 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingInterpreter.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingInterpreter.java @@ -17,27 +17,18 @@ package com.intellij.codeInsight.template.zencoding; import com.intellij.codeInsight.template.CustomTemplateCallback; import com.intellij.codeInsight.template.impl.TemplateImpl; -import com.intellij.lang.ASTNode; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.xml.XmlChildRole; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlToken; import com.intellij.psi.xml.XmlTokenType; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.IntArrayList; -import com.intellij.xml.util.HtmlUtil; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -48,7 +39,6 @@ import java.util.*; class XmlZenCodingInterpreter { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.template.zencoding.XmlZenCodingInterpreter"); private static final String ATTRS = "ATTRS"; - private static final String NUMBER_IN_ITERATION_PLACE_HOLDER = "$"; private final List myTokens; @@ -79,7 +69,7 @@ class XmlZenCodingInterpreter { PsiFile file = myCallback.parseCurrentText(StdFileTypes.XML); PsiElement element = file.findElementAt(offset); - if (element instanceof XmlToken && ((XmlToken)element).getTokenType() == XmlTokenType.XML_END_TAG_START) { + if (offset < endOfTemplate && element instanceof XmlToken && ((XmlToken)element).getTokenType() == XmlTokenType.XML_END_TAG_START) { return; } @@ -94,7 +84,9 @@ class XmlZenCodingInterpreter { } if (newOffset >= 0) { - myCallback.fixEndOffset(); + if (offset < endOfTemplate) { + myCallback.fixEndOffset(); + } myCallback.moveToOffset(newOffset); } } @@ -112,6 +104,15 @@ class XmlZenCodingInterpreter { } private void invoke(int startIndex) { + String filter = null; + + if (myTokens.size() > 0) { + Token lastToken = myTokens.get(myTokens.size() - 1); + if (lastToken instanceof FilterToken) { + filter = ((FilterToken)lastToken).getSuffix(); + } + } + final int n = myTokens.size(); TemplateToken templateToken = null; int number = -1; @@ -121,11 +122,11 @@ class XmlZenCodingInterpreter { case OPERATION: if (templateToken != null) { if (token instanceof MarkerToken || token instanceof OperationToken) { - final char sign = token instanceof OperationToken ? ((OperationToken)token).mySign : ZenCodingTemplate.MARKER; + final char sign = token instanceof OperationToken ? ((OperationToken)token).getSign() : ZenCodingTemplate.MARKER; if (sign == '+' || (mySurroundedText == null && sign == ZenCodingTemplate.MARKER)) { final Object key = new Object(); myCallback.fixStartOfTemplate(key); - invokeTemplate(templateToken, myCallback, 0); + invokeTemplate(templateToken, myCallback, 0, filter); myState = State.WORD; if (myCallback.getOffset() != myCallback.getEndOfTemplate(key)) { myCallback.fixEndOffset(); @@ -136,7 +137,7 @@ class XmlZenCodingInterpreter { templateToken = null; } else if (sign == '>' || (mySurroundedText != null && sign == ZenCodingTemplate.MARKER)) { - startTemplateAndGotoChild(templateToken); + startTemplateAndGotoChild(templateToken, filter); templateToken = null; } else if (sign == '*') { @@ -159,7 +160,7 @@ class XmlZenCodingInterpreter { break; case NUMBER: if (token instanceof NumberToken) { - number = ((NumberToken)token).myNumber; + number = ((NumberToken)token).getNumber(); myState = State.AFTER_NUMBER; } else { @@ -168,18 +169,18 @@ class XmlZenCodingInterpreter { break; case AFTER_NUMBER: if (token instanceof MarkerToken || token instanceof OperationToken) { - char sign = token instanceof OperationToken ? ((OperationToken)token).mySign : ZenCodingTemplate.MARKER; + char sign = token instanceof OperationToken ? ((OperationToken)token).getSign() : ZenCodingTemplate.MARKER; if (sign == '+' || (mySurroundedText == null && sign == ZenCodingTemplate.MARKER)) { - invokeTemplateSeveralTimes(templateToken, 0, number); + invokeTemplateSeveralTimes(templateToken, 0, number, filter); templateToken = null; } else if (number > 1) { - invokeTemplateAndProcessTail(templateToken, 0, number, i + 1); + invokeTemplateAndProcessTail(templateToken, 0, number, i + 1, filter); return; } else { assert number == 1; - startTemplateAndGotoChild(templateToken); + startTemplateAndGotoChild(templateToken, filter); templateToken = null; } myState = State.WORD; @@ -196,21 +197,22 @@ class XmlZenCodingInterpreter { finish(); } - private void startTemplateAndGotoChild(TemplateToken templateToken) { + private void startTemplateAndGotoChild(TemplateToken templateToken, String filter) { final Object key = new Object(); myCallback.fixStartOfTemplate(key); - invokeTemplate(templateToken, myCallback, 0); + invokeTemplate(templateToken, myCallback, 0, filter); myState = State.WORD; gotoChild(key); } private void invokeTemplateSeveralTimes(final TemplateToken templateToken, final int startIndex, - final int count) { + final int count, + String filter) { final Object key = new Object(); myCallback.fixStartOfTemplate(key); for (int i = startIndex; i < count; i++) { - invokeTemplate(templateToken, myCallback, i); + invokeTemplate(templateToken, myCallback, i, filter); myState = State.WORD; if (myCallback.getOffset() != myCallback.getEndOfTemplate(key)) { myCallback.fixEndOffset(); @@ -227,12 +229,15 @@ class XmlZenCodingInterpreter { private void invokeTemplateAndProcessTail(final TemplateToken templateToken, final int startIndex, final int count, - final int tailStart) { + final int tailStart, + String filter) { final Object key = new Object(); myCallback.fixStartOfTemplate(key); for (int i = startIndex; i < count; i++) { - invokeTemplate(templateToken, myCallback, i); - gotoChild(key); + Object iterKey = new Object(); + myCallback.fixStartOfTemplate(iterKey); + invokeTemplate(templateToken, myCallback, i, filter); + gotoChild(iterKey); interpret(myTokens, tailStart, myCallback, State.WORD, mySurroundedText); if (myCallback.getOffset() != myCallback.getEndOfTemplate(key)) { myCallback.fixEndOffset(); @@ -242,7 +247,7 @@ class XmlZenCodingInterpreter { finish(); } - private static boolean containsAttrsVar(TemplateImpl template) { + static boolean containsAttrsVar(TemplateImpl template) { for (int i = 0; i < template.getVariableCount(); i++) { String varName = template.getVariableNameAt(i); if (ATTRS.equals(varName)) { @@ -270,18 +275,11 @@ class XmlZenCodingInterpreter { } @Nullable - private static Map buildPredefinedValues(List> attribute2value, int numberInIteration) { - StringBuilder result = new StringBuilder(); - for (Iterator> it = attribute2value.iterator(); it.hasNext();) { - Pair pair = it.next(); - String name = pair.first; - String value = getValue(pair, numberInIteration); - result.append(name).append("=\"").append(value).append('"'); - if (it.hasNext()) { - result.append(' '); - } - } - String attributes = result.toString(); + private static Map buildPredefinedValues(List> attribute2value, + int numberInIteration, + CustomTemplateCallback callback) { + String attributes = buildAttributesString(attribute2value, numberInIteration, callback); + assert attributes != null; attributes = attributes.length() > 0 ? ' ' + attributes : null; Map predefinedValues = null; if (attributes != null) { @@ -291,149 +289,66 @@ class XmlZenCodingInterpreter { return predefinedValues; } - private static String getValue(Pair pair, int numberInIteration) { - return pair.second.replace(NUMBER_IN_ITERATION_PLACE_HOLDER, Integer.toString(numberInIteration + 1)); + @Nullable + private static String buildAttributesString(List> attribute2value, + int numberInIteration, + CustomTemplateCallback callback) { + PsiElement context = callback.getContext(); + for (ZenCodingFilter filter : ZenCodingFilter.EP_NAME.getExtensions()) { + if (filter.isMyContext(context)) { + return filter.buildAttributesString(attribute2value, numberInIteration); + } + } + return new XmlZenCodingFilterImpl().buildAttributesString(attribute2value, numberInIteration); } - @Nullable - private static String addAttrsVar(TemplateImpl modifiedTemplate, XmlTag tag) { - String text = tag.getContainingFile().getText(); - PsiElement[] children = tag.getChildren(); - if (children.length >= 1 && - children[0] instanceof XmlToken && - ((XmlToken)children[0]).getTokenType() == XmlTokenType.XML_START_TAG_START) { - PsiElement beforeAttrs = children[0]; - if (children.length >= 2 && children[1] instanceof XmlToken && ((XmlToken)children[1]).getTokenType() == XmlTokenType.XML_NAME) { - beforeAttrs = children[1]; - } - TextRange range = beforeAttrs.getTextRange(); - if (range == null) { - return null; - } - int offset = range.getEndOffset(); - text = text.substring(0, offset) + " $ATTRS$" + text.substring(offset); - modifiedTemplate.addVariable(ATTRS, "", "", false); - return text; - } - return null; - } private static void invokeTemplate(TemplateToken token, final CustomTemplateCallback callback, - int numberInIteration) { - List> attr2value = new ArrayList>(token.myAttribute2Value); - if (callback.isLiveTemplateApplicable(token.myKey)) { - invokeExistingLiveTemplate(token, callback, numberInIteration, attr2value); - } - else { - TemplateImpl template = new TemplateImpl("", ""); - template.addTextSegment('<' + token.myKey); - if (attr2value.size() > 0) { - template.addVariable(ATTRS, "", "", false); - template.addVariableSegment(ATTRS); - } - template.addTextSegment(">"); - if (XmlZenCodingTemplate.isTrueXml(callback) || !HtmlUtil.isSingleHtmlTag(token.myKey)) { - template.addVariableSegment(TemplateImpl.END); - template.addTextSegment(""); - } - template.setToReformat(true); - Map predefinedValues = buildPredefinedValues(attr2value, numberInIteration); - callback.expandTemplate(template, predefinedValues); - } - } - - private static void invokeExistingLiveTemplate(TemplateToken token, - CustomTemplateCallback callback, - int numberInIteration, - List> attr2value) { - if (token.myTemplate != null) { + int numberInIteration, + String filter) { + if (token instanceof XmlTemplateToken && token.getTemplate() != null) { + XmlTemplateToken xmlTemplateToken = (XmlTemplateToken)token; + List> attr2value = new ArrayList>(xmlTemplateToken.getAttribute2Value()); if (attr2value.size() > 0 || XmlZenCodingTemplate.isTrueXml(callback)) { - TemplateImpl modifiedTemplate = token.myTemplate.copy(); - XmlTag tag = XmlZenCodingTemplate.parseXmlTagInTemplate(token.myTemplate.getString(), callback, true); + TemplateImpl modifiedTemplate = token.getTemplate().copy(); + XmlTag tag = xmlTemplateToken.getTag(); if (tag != null) { for (Iterator> iterator = attr2value.iterator(); iterator.hasNext();) { Pair pair = iterator.next(); if (tag.getAttribute(pair.first) != null) { - tag.setAttribute(pair.first, getValue(pair, numberInIteration)); + tag.setAttribute(pair.first, ZenCodingUtil.getValue(pair, numberInIteration)); iterator.remove(); } } - if (XmlZenCodingTemplate.isTrueXml(callback)) { - closeUnclosingTags(tag); - } - String text = null; - if (!containsAttrsVar(modifiedTemplate) && attr2value.size() > 0) { - String textWithAttrs = addAttrsVar(modifiedTemplate, tag); - if (textWithAttrs != null) { - text = textWithAttrs; - } - else { - for (Iterator> iterator = attr2value.iterator(); iterator.hasNext();) { - Pair pair = iterator.next(); - tag.setAttribute(pair.first, getValue(pair, numberInIteration)); - iterator.remove(); - } - } - } - if (text == null) { - text = tag.getContainingFile().getText(); - } - modifiedTemplate.setString(text); + String s = filterXml(tag, callback, filter); + assert s != null; + modifiedTemplate.setString(s); removeVariablesWhichHasNoSegment(modifiedTemplate); - Map predefinedValues = buildPredefinedValues(attr2value, numberInIteration); + Map predefinedValues = buildPredefinedValues(attr2value, numberInIteration, callback); callback.expandTemplate(modifiedTemplate, predefinedValues); return; } } - callback.expandTemplate(token.myTemplate, null); + callback.expandTemplate(token.getTemplate(), null); } else { - Map predefinedValues = buildPredefinedValues(attr2value, numberInIteration); - callback.expandTemplate(token.myKey, predefinedValues); + // for CSS + callback.expandTemplate(token.getKey(), null); } } - private static boolean isTagClosed(@NotNull XmlTag tag) { - ASTNode node = tag.getNode(); - assert node != null; - final ASTNode emptyTagEnd = XmlChildRole.EMPTY_TAG_END_FINDER.findChild(node); - final ASTNode endTagEnd = XmlChildRole.CLOSING_TAG_START_FINDER.findChild(node); - return emptyTagEnd != null || endTagEnd != null; - } - - @SuppressWarnings({"ConstantConditions"}) - private static void closeUnclosingTags(@NotNull XmlTag root) { - final List> tagToClose = new ArrayList>(); - Project project = root.getProject(); - final SmartPointerManager manager = SmartPointerManager.getInstance(project); - root.accept(new XmlRecursiveElementVisitor() { - @Override - public void visitXmlTag(final XmlTag tag) { - if (!isTagClosed(tag)) { - tagToClose.add(manager.createLazyPointer(tag)); - } - } - }); - for (final SmartPsiElementPointer pointer : tagToClose) { - final XmlTag tag = pointer.getElement(); - if (tag != null) { - final ASTNode child = XmlChildRole.START_TAG_END_FINDER.findChild(tag.getNode()); - if (child != null) { - final int offset = child.getTextRange().getStartOffset(); - VirtualFile file = tag.getContainingFile().getVirtualFile(); - if (file != null) { - final Document document = FileDocumentManager.getInstance().getDocument(file); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - document.replaceString(offset, tag.getTextRange().getEndOffset(), "/>"); - } - }); - } + @Nullable + private static String filterXml(XmlTag tag, CustomTemplateCallback callback, String filterSuffix) { + PsiElement context = callback.getContext(); + for (ZenCodingFilter filter : ZenCodingFilter.EP_NAME.getExtensions()) { + if ((filterSuffix == null && filter.isDefaultFilter()) || (filterSuffix != null && filterSuffix.equals(filter.getSuffix()))) { + if (filter instanceof XmlZenCodingFilter && filter.isDefaultFilter() && filter.isMyContext(context)) { + return ((XmlZenCodingFilter)filter).toString(tag, context); } } } - PsiDocumentManager.getInstance(project).commitAllDocuments(); + return new XmlZenCodingFilterImpl().toString(tag, context); } private static void fail() { diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingTemplate.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingTemplate.java index ab40993e31d7..080397ba94f5 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingTemplate.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/XmlZenCodingTemplate.java @@ -27,15 +27,18 @@ import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; +import com.intellij.psi.XmlElementFactory; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.*; import com.intellij.util.LocalTimeCounter; import com.intellij.util.containers.HashSet; +import com.intellij.xml.util.HtmlUtil; import org.apache.xerces.util.XML11Char; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Set; @@ -68,7 +71,7 @@ public class XmlZenCodingTemplate extends ZenCodingTemplate { } @Nullable - private static TemplateToken parseSelectors(@NotNull String text) { + private static XmlTemplateToken parseSelectors(@NotNull String text) { String templateKey = null; List> attributes = new ArrayList>(); Set definedAttrs = new HashSet(); @@ -140,7 +143,7 @@ public class XmlZenCodingTemplate extends ZenCodingTemplate { assert classAttrPosition >= 0; attributes.add(classAttrPosition, new Pair(CLASS, classesAttrValue.toString())); } - return new TemplateToken(templateKey, attributes); + return new XmlTemplateToken(templateKey, attributes); } private static boolean isXML11ValidQName(String str) { @@ -157,7 +160,10 @@ public class XmlZenCodingTemplate extends ZenCodingTemplate { } public static boolean isTrueXml(CustomTemplateCallback callback) { - FileType type = callback.getFileType(); + return isTrueXml(callback.getFileType()); + } + + public static boolean isTrueXml(FileType type) { return type == StdFileTypes.XHTML || type == StdFileTypes.JSPX || type == StdFileTypes.XML; } @@ -185,26 +191,67 @@ public class XmlZenCodingTemplate extends ZenCodingTemplate { if (template == null && !isXML11ValidQName(prefix)) { return null; } - TemplateToken token = parseSelectors(key); + XmlTemplateToken token = parseSelectors(key); if (token == null) { return null; } - if (useDefaultTag && token.myAttribute2Value.size() == 0) { + if (useDefaultTag && token.getAttribute2Value().size() == 0) { return null; } - if (template != null && (token.myAttribute2Value.size() > 0 || isTrueXml(callback))) { - assert prefix.equals(token.myKey); - token.myTemplate = template; - if (token.myAttribute2Value.size() > 0) { - XmlTag tag = parseXmlTagInTemplate(template.getString(), callback, false); - if (tag == null) { - return null; - } + if (template == null) { + template = generateTagTemplate(token.getKey(), callback); + } + assert prefix.equals(token.getKey()); + token.setTemplate(template); + XmlTag tag = parseXmlTagInTemplate(template.getString(), callback, true); + if (token.getAttribute2Value().size() > 0 && tag == null) { + return null; + } + if (tag != null) { + if (!XmlZenCodingInterpreter.containsAttrsVar(template) && token.getAttribute2Value().size() > 0) { + addMissingAttributes(tag, token.getAttribute2Value()); } + token.setTag(tag); } return token; } + private static void addMissingAttributes(XmlTag tag, List> value) { + List> attr2value = new ArrayList>(value); + for (Iterator> iterator = attr2value.iterator(); iterator.hasNext();) { + Pair pair = iterator.next(); + if (tag.getAttribute(pair.first) != null) { + iterator.remove(); + } + } + addAttributesBefore(tag, attr2value); + } + + private static void addAttributesBefore(XmlTag tag, List> attr2value) { + XmlAttribute[] attributes = tag.getAttributes(); + XmlAttribute firstAttribute = attributes.length > 0 ? attributes[0] : null; + XmlElementFactory factory = XmlElementFactory.getInstance(tag.getProject()); + for (Pair pair : attr2value) { + XmlAttribute xmlAttribute = factory.createXmlAttribute(pair.first, ""); + if (firstAttribute != null) { + tag.addBefore(xmlAttribute, firstAttribute); + } + else { + tag.add(xmlAttribute); + } + } + } + + @NotNull + private static TemplateImpl generateTagTemplate(String tagName, CustomTemplateCallback callback) { + StringBuilder builder = new StringBuilder("<"); + builder.append(tagName).append('>'); + if (isTrueXml(callback) || !HtmlUtil.isSingleHtmlTag(tagName)) { + builder.append("$END$'); + } + return new TemplateImpl("", builder.toString(), ""); + } + @Nullable static XmlTag parseXmlTagInTemplate(String templateString, CustomTemplateCallback callback, boolean createPhysicalFile) { XmlFile xmlFile = (XmlFile)PsiFileFactory.getInstance(callback.getProject()) @@ -221,11 +268,23 @@ public class XmlZenCodingTemplate extends ZenCodingTemplate { if (PsiTreeUtil.getParentOfType(element, XmlComment.class) != null) { return false; } + if (!findApplicableFilter(element)) { + return false; + } return true; } return false; } + private static boolean findApplicableFilter(@NotNull PsiElement context) { + for (ZenCodingFilter filter : ZenCodingFilter.EP_NAME.getExtensions()) { + if (filter.isMyContext(context)) { + return true; + } + } + return new XmlZenCodingFilterImpl().isMyContext(context); + } + public static boolean startZenCoding(Editor editor, PsiFile file, String abbreviation) { int caretAt = editor.getCaretModel().getOffset(); XmlZenCodingTemplate template = CustomLiveTemplate.EP_NAME.findExtension(XmlZenCodingTemplate.class); diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingFilter.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingFilter.java new file mode 100644 index 000000000000..1a92cc307b7b --- /dev/null +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingFilter.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.template.zencoding; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +public interface ZenCodingFilter { + ExtensionPointName EP_NAME = new ExtensionPointName("com.intellij.xml.zenCodingFilter"); + + @NotNull + String toString(@NotNull TemplateToken token, @NotNull PsiElement context); + + @NotNull + String buildAttributesString(@NotNull List> attribute2value, int numberInIteration); + + boolean isMyContext(@NotNull PsiElement context); + + @Nullable + String getSuffix(); + + boolean isDefaultFilter(); +} diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingTemplate.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingTemplate.java index 9f0257f01e25..392b0c3d2500 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingTemplate.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingTemplate.java @@ -55,6 +55,14 @@ public abstract class ZenCodingTemplate implements CustomLiveTemplate { @Nullable private List parse(@NotNull String text, @NotNull CustomTemplateCallback callback) { + String filter = null; + + int filterDelim = text.indexOf('|'); + if (filterDelim >= 0 && filterDelim < text.length() - 1) { + filter = text.substring(filterDelim + 1); + text = text.substring(0, filterDelim); + } + text += MARKER; StringBuilder templateKeyBuilder = new StringBuilder(); List result = new ArrayList(); @@ -81,6 +89,10 @@ public abstract class ZenCodingTemplate implements CustomLiveTemplate { return null; } } + + if (filter != null) { + result.add(new FilterToken(filter)); + } return result; } @@ -96,7 +108,7 @@ public abstract class ZenCodingTemplate implements CustomLiveTemplate { switch (state) { case OPERATION: if (token instanceof OperationToken) { - state = ((OperationToken)token).mySign == '*' ? State.NUMBER : State.WORD; + state = ((OperationToken)token).getSign() == '*' ? State.NUMBER : State.WORD; } else { return false; @@ -119,7 +131,7 @@ public abstract class ZenCodingTemplate implements CustomLiveTemplate { } break; case AFTER_NUMBER: - if (token instanceof OperationToken && ((OperationToken)token).mySign != '*') { + if (token instanceof OperationToken && ((OperationToken)token).getSign() != '*') { state = State.WORD; } else { @@ -154,16 +166,6 @@ public abstract class ZenCodingTemplate implements CustomLiveTemplate { protected boolean checkTemplateKey(String key, CustomTemplateCallback callback) { List tokens = parse(key, callback); if (tokens != null && check(tokens)) { - // !! required if Zen Coding if invoked by TemplateManagerImpl action - /*if (tokens.size() == 2) { - Token token = tokens.get(0); - if (token instanceof TemplateToken) { - if (key.equals(((TemplateToken)token).myKey) && callback.isLiveTemplateApplicable(key)) { - // do not activate only live template - return null; - } - } - }*/ return true; } return false; @@ -182,7 +184,7 @@ public abstract class ZenCodingTemplate implements CustomLiveTemplate { if (tokens.size() == 2) { Token token = tokens.get(0); if (token instanceof TemplateToken) { - if (key.equals(((TemplateToken)token).myKey) && callback.findApplicableTemplates(key).size() > 1) { + if (key.equals(((TemplateToken)token).getKey()) && callback.findApplicableTemplates(key).size() > 1) { callback.startTemplate(); return; } diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingUtil.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingUtil.java new file mode 100644 index 000000000000..c29d17638811 --- /dev/null +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingUtil.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.template.zencoding; + +import com.intellij.openapi.util.Pair; + +/** + * @author Eugene.Kudelevsky + */ +public class ZenCodingUtil { + static final String NUMBER_IN_ITERATION_PLACE_HOLDER = "$"; + + public static String getValue(Pair pair, int numberInIteration) { + return pair.second.replace(NUMBER_IN_ITERATION_PLACE_HOLDER, Integer.toString(numberInIteration + 1)); + } +} diff --git a/xml/impl/src/com/intellij/psi/formatter/xml/AbstractXmlBlock.java b/xml/impl/src/com/intellij/psi/formatter/xml/AbstractXmlBlock.java index d63426513886..3dc996af65d2 100644 --- a/xml/impl/src/com/intellij/psi/formatter/xml/AbstractXmlBlock.java +++ b/xml/impl/src/com/intellij/psi/formatter/xml/AbstractXmlBlock.java @@ -260,18 +260,6 @@ public abstract class AbstractXmlBlock extends AbstractBlock { } ); } - else if (child.getElementType() == XmlElementType.XML_ATTRIBUTE_VALUE) { - // - // Fix for EA-19269: - // Split XML attribute value to the value itself and delimiters (needed for the case when it contains - // template language tags inside). - // - ASTNode node = child.getFirstChildNode(); - while (node != null) { - result.add(createSimpleChild(node, null, null, null)); - node = node.getTreeNext(); - } - } else { result.add(createSimpleChild(child, indent, wrap, alignment)); } diff --git a/xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java b/xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java index 790ba2ff1cdc..7c774f7ff7a3 100644 --- a/xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java +++ b/xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java @@ -63,8 +63,17 @@ public class XmlBlock extends AbstractXmlBlock { protected List buildChildren() { - if (myNode.getElementType() == XmlElementType.XML_ATTRIBUTE_VALUE || myNode.getElementType() == XmlElementType.XML_COMMENT) { - return EMPTY; + // + // Fix for EA-19269: + // Split XML attribute value to the value itself and delimiters (needed for the case when it contains + // template language tags inside). + // + if (myNode.getElementType() == XmlElementType.XML_ATTRIBUTE_VALUE) { + return splitAttribute(myNode, myXmlFormattingPolicy); + } + + if (myNode.getElementType() == XmlElementType.XML_COMMENT) { + return splitComment(); } if (myNode.getElementType() == XmlElementType.XML_TEXT) { @@ -100,6 +109,43 @@ public class XmlBlock extends AbstractXmlBlock { } } + private static List splitAttribute(ASTNode node, XmlFormattingPolicy formattingPolicy) { + final ArrayList result = new ArrayList(3); + ASTNode child = node.getFirstChildNode(); + while (child != null) { + if (child.getElementType() == XmlElementType.XML_ATTRIBUTE_VALUE_START_DELIMITER || + child.getElementType() == XmlElementType.XML_ATTRIBUTE_VALUE_END_DELIMITER) { + result.add(new XmlBlock(child, null, null, formattingPolicy, null, null)); + } + else { + result.add(new ReadOnlyBlock(child)); + } + child = child.getTreeNext(); + } + return result; + } + + + private List splitComment() { + if (myNode.getElementType() != XmlElementType.XML_COMMENT) return null; + // + // Do not build subblocks for comment-only node. + if (myNode.getFirstChildNode() != null && + myNode.getFirstChildNode().getElementType() == XmlElementType.XML_COMMENT_START && + myNode.getLastChildNode().getElementType() == XmlElementType.XML_COMMENT_END) { + return EMPTY; + } + final ArrayList result = new ArrayList(3); + final ArrayList commentBlocks = new ArrayList(3); + ASTNode child = myNode.getFirstChildNode(); + while (child != null) { + IElementType childType = child.getElementType(); + result.add(new XmlBlock(child, null, null, myXmlFormattingPolicy, getChildIndent(), null)); + child = child.getTreeNext(); + } + return result; + } + protected @Nullable Wrap getDefaultWrap(ASTNode node) { return null; }