diff --git a/.idea/libraries/JUnit5.xml b/.idea/libraries/JUnit5.xml new file mode 100644 index 000000000000..26c9d8a3ac34 --- /dev/null +++ b/.idea/libraries/JUnit5.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/junit5_rt.xml b/.idea/libraries/junit5_rt.xml index a15401fec926..6a87b4890e8e 100644 --- a/.idea/libraries/junit5_rt.xml +++ b/.idea/libraries/junit5_rt.xml @@ -1,16 +1,20 @@ - + + - - - - - - - - + + + + + - + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/opentest4j.xml b/.idea/libraries/opentest4j.xml deleted file mode 100644 index a950465a1404..000000000000 --- a/.idea/libraries/opentest4j.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 9710d229ab8d..e250ab20b6c6 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -20,7 +20,6 @@ - diff --git a/bin/win/elevator.exe b/bin/win/elevator.exe index 8e04f0477a0b..d877c1d6a80f 100644 Binary files a/bin/win/elevator.exe and b/bin/win/elevator.exe differ diff --git a/bin/win/launcher.exe b/bin/win/launcher.exe index 9c70c3befd69..e63f3515ec0d 100644 Binary files a/bin/win/launcher.exe and b/bin/win/launcher.exe differ diff --git a/build/conf/nsis/idea.nsi b/build/conf/nsis/idea.nsi index 8ea34892ef86..00790b7a839e 100644 --- a/build/conf/nsis/idea.nsi +++ b/build/conf/nsis/idea.nsi @@ -360,6 +360,7 @@ Function ConfirmDesktopShortcut ${EndIf} customPreActions: Call customPreInstallActions + SetRegView 32 StrCmp "${ASSOCIATION}" "NoAssociation" skip_association StrCpy $R0 ${INSTALL_OPTION_ELEMENTS} push "${ASSOCIATION}" @@ -458,6 +459,7 @@ LicenseLangString myLicenseData ${LANG_JAPANESE} "${LICENSE_FILE}.txt" !endif Function .onInit + SetRegView 32 StrCpy $baseRegKey "HKCU" IfSilent UAC_Done UAC_Elevate: @@ -823,6 +825,7 @@ next_association: done: Call customInstallActions + SetRegView 32 ; registration application to be presented in Open With list call ProductRegistration @@ -873,6 +876,7 @@ skip_ipr: File "${PRODUCT_VM_OPTIONS_FILE}" Call customPostInstallActions + SetRegView 32 StrCpy $0 $baseRegKey StrCpy $1 "Software\${MANUFACTURER}\${PRODUCT_REG_VER}" StrCpy $2 "" @@ -964,6 +968,7 @@ FunctionEnd Function un.onInit + SetRegView 32 Call un.getRegKey StrCmp $baseRegKey "HKLM" requred_admin_perm UAC_Done @@ -1145,6 +1150,7 @@ FunctionEnd Section "Uninstall" Call un.customUninstallActions + SetRegView 32 StrCpy $0 $baseRegKey StrCpy $1 "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_WITH_VER}" StrCpy $2 "InstallLocation" diff --git a/build/dependencies/gradle.properties b/build/dependencies/gradle.properties index ee0ad26ee130..8d4b9a694a7e 100644 --- a/build/dependencies/gradle.properties +++ b/build/dependencies/gradle.properties @@ -1,4 +1,4 @@ # The file might be automatically updated. Comments and empty lines will be removed. kotlinPluginBuild=1.1.4-release-IJ2017.2-3 jetSignBuild=42.30 -jdkBuild=u152b1008.1 +jdkBuild=u152b1012.1 diff --git a/community-main.iml b/community-main.iml index f3fdf6e1e7d0..e8e4332fb865 100644 --- a/community-main.iml +++ b/community-main.iml @@ -115,7 +115,6 @@ - diff --git a/images/src/org/intellij/images/thumbnail/impl/ThumbnailViewUI.java b/images/src/org/intellij/images/thumbnail/impl/ThumbnailViewUI.java index f62d7b4c6334..c146b884424e 100644 --- a/images/src/org/intellij/images/thumbnail/impl/ThumbnailViewUI.java +++ b/images/src/org/intellij/images/thumbnail/impl/ThumbnailViewUI.java @@ -656,6 +656,7 @@ final class ThumbnailViewUI extends JPanel implements DataProvider, Disposable { } private final class VFSListener implements VirtualFileListener { + @Override public void contentsChanged(@NotNull VirtualFileEvent event) { VirtualFile file = event.getFile(); if (list != null) { @@ -667,6 +668,7 @@ final class ThumbnailViewUI extends JPanel implements DataProvider, Disposable { } } + @Override public void fileDeleted(@NotNull VirtualFileEvent event) { VirtualFile file = event.getFile(); VirtualFile root = thumbnailView.getRoot(); @@ -678,14 +680,17 @@ final class ThumbnailViewUI extends JPanel implements DataProvider, Disposable { } } + @Override public void propertyChanged(@NotNull VirtualFilePropertyEvent event) { refresh(); } + @Override public void fileCreated(@NotNull VirtualFileEvent event) { refresh(); } + @Override public void fileMoved(@NotNull VirtualFileMoveEvent event) { refresh(); } diff --git a/java/compiler/impl/src/com/intellij/build/AbstractViewManager.java b/java/compiler/impl/src/com/intellij/build/AbstractViewManager.java index ccd6b6bc0008..3c53cd55cf3b 100644 --- a/java/compiler/impl/src/com/intellij/build/AbstractViewManager.java +++ b/java/compiler/impl/src/com/intellij/build/AbstractViewManager.java @@ -16,6 +16,7 @@ package com.intellij.build; import com.intellij.build.events.*; +import com.intellij.execution.filters.Filter; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.ui.*; import com.intellij.execution.ui.layout.impl.RunnerLayoutUiImpl; @@ -44,16 +45,15 @@ import com.intellij.util.ui.EdtInvocationManager; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.*; -import java.util.ArrayList; +import java.util.*; import java.util.List; -import java.util.Map; -import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; @@ -62,8 +62,8 @@ import java.util.function.Supplier; * @author Vladislav.Soroka */ public abstract class AbstractViewManager implements BuildProgressListener, Disposable { - private final Project myProject; - private final BuildContentManager myBuildContentManager; + protected final Project myProject; + protected final BuildContentManager myBuildContentManager; private final AtomicBoolean isInitializeStarted; private final List myPostponedRunnables; private final ProgressWatcher myProgressWatcher; @@ -90,7 +90,7 @@ public abstract class AbstractViewManager implements BuildProgressListener, Disp JPanel panel = new JPanel(new BorderLayout()); SimpleColoredComponent mainComponent = new SimpleColoredComponent(); mainComponent.setIcon(buildInfo.getIcon()); - mainComponent.append(buildInfo.title + ": ", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); + mainComponent.append(buildInfo.getTitle() + ": ", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); mainComponent.append(buildInfo.message, SimpleTextAttributes.REGULAR_ATTRIBUTES); panel.add(mainComponent, BorderLayout.NORTH); if (buildInfo.statusMessage != null) { @@ -116,6 +116,10 @@ public abstract class AbstractViewManager implements BuildProgressListener, Disp return false; } + protected Map getBuildsMap() { + return Collections.unmodifiableMap(myViewMap); + } + @Override public void onEvent(BuildEvent event) { List runnables = new SmartList<>(); @@ -145,11 +149,18 @@ public abstract class AbstractViewManager implements BuildProgressListener, Disp myToolbarActions.removeAll(); } } + myBuildsMap.computeIfAbsent(ObjectUtils.chooseNotNull( + event.getParentId(), event.getId()), o -> { + StartBuildEvent startBuildEvent = (StartBuildEvent)event; + return new BuildInfo(event.getId(), startBuildEvent.getBuildTitle(), startBuildEvent.getWorkingDir(), event.getEventTime()); + }); } - final BuildInfo buildInfo = - myBuildsMap.computeIfAbsent(ObjectUtils.chooseNotNull(event.getParentId(), event.getId()), o -> new BuildInfo()); - if (event.getParentId() != null) { - myBuildsMap.put(event.getId(), buildInfo); + else { + if (event.getParentId() != null) { + BuildInfo buildInfo = myBuildsMap.get(event.getParentId()); + assert buildInfo != null; + myBuildsMap.put(event.getId(), buildInfo); + } } }); @@ -157,8 +168,6 @@ public abstract class AbstractViewManager implements BuildProgressListener, Disp final BuildInfo buildInfo = myBuildsMap.get(event.getId()); assert buildInfo != null; if (event instanceof StartBuildEvent) { - buildInfo.title = ((StartBuildEvent)event).getBuildTitle(); - buildInfo.id = event.getId(); buildInfo.message = event.getMessage(); if (!isTabbedView() && myBuildsList != null) { @@ -166,60 +175,77 @@ public abstract class AbstractViewManager implements BuildProgressListener, Disp listModel.addElement(buildInfo); } + final RunContentDescriptor contentDescriptor; + Supplier contentDescriptorSupplier = ((StartBuildEvent)event).getContentDescriptorSupplier(); + contentDescriptor = contentDescriptorSupplier != null ? contentDescriptorSupplier.get() : null; ProcessHandler processHandler = ((StartBuildEvent)event).getProcessHandler(); BuildView view = myViewMap.computeIfAbsent(buildInfo, info -> { ExecutionConsole executionConsole = null; - ComponentContainer componentContainer = null; - Supplier contentDescriptorSupplier = ((StartBuildEvent)event).getContentDescriptorSupplier(); - if (contentDescriptorSupplier != null) { - RunContentDescriptor contentDescriptor = contentDescriptorSupplier.get(); - if (contentDescriptor != null) { - executionConsole = contentDescriptor.getExecutionConsole(); - List leftToolbarActions = ContainerUtil.newArrayList(); - RunnerLayoutUi layoutUi = contentDescriptor.getRunnerLayoutUi(); - if (layoutUi instanceof RunnerLayoutUiImpl) { - RunnerLayoutUiImpl layoutUiImpl = (RunnerLayoutUiImpl)layoutUi; - layoutUiImpl.setLeftToolbarVisible(false); - layoutUiImpl.setContentToolbarBefore(false); - leftToolbarActions.addAll(layoutUiImpl.getActions()); + BuildConsoleView buildConsoleView = null; + if (contentDescriptor != null) { + executionConsole = contentDescriptor.getExecutionConsole(); + List leftToolbarActions = ContainerUtil.newArrayList(); + RunnerLayoutUi layoutUi = contentDescriptor.getRunnerLayoutUi(); + if (layoutUi instanceof RunnerLayoutUiImpl) { + RunnerLayoutUiImpl layoutUiImpl = (RunnerLayoutUiImpl)layoutUi; + layoutUiImpl.setLeftToolbarVisible(false); + layoutUiImpl.setContentToolbarBefore(false); + leftToolbarActions.addAll(layoutUiImpl.getActions()); + } + JComponent component = contentDescriptor.getComponent(); + AnAction[] leftToolbarActionsArray = leftToolbarActions.toArray(new AnAction[leftToolbarActions.size()]); + buildConsoleView = new BuildConsoleView() { + @Override + public void onEvent(BuildEvent event) { } - JComponent component = contentDescriptor.getComponent(); - AnAction[] leftToolbarActionsArray = leftToolbarActions.toArray(new AnAction[leftToolbarActions.size()]); - componentContainer = new BuildConsoleView() { - @Override - public void onEvent(BuildEvent event) { - } - @Override - public AnAction[] createConsoleActions() { - return leftToolbarActionsArray; - } + @Override + public AnAction[] createConsoleActions() { + return leftToolbarActionsArray; + } - @Override - public JComponent getComponent() { - return component; - } + @Override + public JComponent getComponent() { + return component; + } - @Override - public JComponent getPreferredFocusableComponent() { - return component; - } + @Override + public JComponent getPreferredFocusableComponent() { + ExecutionConsole console = contentDescriptor.getExecutionConsole(); + if (console != null) return console.getPreferredFocusableComponent(); + return (component instanceof ComponentContainer) + ? ((ComponentContainer)component).getPreferredFocusableComponent() + : component; + } - @Override - public void dispose() { - } - }; + @Override + public void dispose() { + } + }; + Disposer.register(buildConsoleView, contentDescriptor); + } + if (buildConsoleView == null) { + buildConsoleView = new BuildTextConsoleView(myProject); + executionConsole = (ExecutionConsole)buildConsoleView; + } + if (executionConsole instanceof ConsoleView) { + for (Filter filter : ((StartBuildEvent)event).getExecutionFilters()) { + ((ConsoleView)executionConsole).addMessageFilter(filter); } } - if (componentContainer == null) { - componentContainer = executionConsole = new BuildTextConsoleView(myProject); - } + final BuildView buildView = - new BuildView(myProject, componentContainer, ((StartBuildEvent)event), + new BuildView(myProject, buildConsoleView, ((StartBuildEvent)event), "build.toolwindow." + getViewName() + ".selection.state", isConsoleEnabledByDefault()); if (processHandler != null) { - if (executionConsole instanceof ConsoleView) { - ((ConsoleView)executionConsole).attachToProcess(processHandler); + if (buildConsoleView instanceof ConsoleView) { + ((ConsoleView)buildConsoleView).attachToProcess(processHandler); + Consumer attachedConsoleConsumer = ((StartBuildEvent)event).getAttachedConsoleConsumer(); + if (attachedConsoleConsumer != null) { + attachedConsoleConsumer.consume((ConsoleView)buildConsoleView); + } + } + else if (executionConsole instanceof ConsoleView) { Consumer attachedConsoleConsumer = ((StartBuildEvent)event).getAttachedConsoleConsumer(); if (attachedConsoleConsumer != null) { attachedConsoleConsumer.consume((ConsoleView)executionConsole); @@ -237,22 +263,33 @@ public abstract class AbstractViewManager implements BuildProgressListener, Disp consoleComponent.add(ActionManager.getInstance().createActionToolbar( "BuildView", toolbarActions, false).getComponent(), BorderLayout.WEST); toolbarActions.addAll(buildView.createConsoleActions()); + Icon contentIcon = getContentIcon(); myContent = myBuildContentManager.addTabbedContent( - consoleComponent, getViewName(), buildInfo.title + ", " + DateFormatUtil.formatDateTime(System.currentTimeMillis()) + " ", - true, AllIcons.CodeStyle.Gear, buildView); + consoleComponent, getViewName(), + buildInfo.getTitle() + ", " + DateFormatUtil.formatDateTime(System.currentTimeMillis()) + " ", + contentIcon, buildView); } return buildView; }); + if (contentDescriptor != null) { + boolean activateToolWindow = contentDescriptor.isActivateToolWindowWhenAdded(); + buildInfo.activateToolWindowWhenAdded = activateToolWindow; + boolean focusContent = contentDescriptor.isAutoFocusContent(); + myBuildContentManager.setSelectedContent( + myContent, focusContent, focusContent, activateToolWindow, contentDescriptor.getActivationCallback()); + } + else { + myBuildContentManager.setSelectedContent(myContent, true, true, true, null); + } + buildInfo.content = myContent; + if (!isTabbedView() && myThreeComponentsSplitter.getLastComponent() == null) { myThreeComponentsSplitter.setLastComponent(view); myToolbarActions.removeAll(); myToolbarActions.addAll(view.createConsoleActions()); } - if (!isTabbedView() && - myBuildsList != null && - myBuildsList.getModel().getSize() > 1 && - myThreeComponentsSplitter.getFirstComponent() == null) { + if (!isTabbedView() && myBuildsList != null && myBuildsList.getModel().getSize() > 1) { JBScrollPane scrollPane = new JBScrollPane(); scrollPane.setBorder(JBUI.Borders.empty()); scrollPane.setViewportView(myBuildsList); @@ -271,10 +308,11 @@ public abstract class AbstractViewManager implements BuildProgressListener, Disp else { myThreeComponentsSplitter.setFirstComponent(null); } + onBuildStart(buildInfo); myProgressWatcher.addBuild(buildInfo); //view.getPrimaryView().print("\r", ConsoleViewContentType.SYSTEM_OUTPUT); - ((BuildContentManagerImpl)myBuildContentManager).startBuildNotified(myContent); + ((BuildContentManagerImpl)myBuildContentManager).startBuildNotified(buildInfo.content); } else { if (event instanceof FinishBuildEvent) { @@ -282,7 +320,8 @@ public abstract class AbstractViewManager implements BuildProgressListener, Disp buildInfo.message = event.getMessage(); buildInfo.result = ((FinishBuildEvent)event).getResult(); myProgressWatcher.stopBuild(buildInfo); - ((BuildContentManagerImpl)myBuildContentManager).finishBuildNotified(myContent); + ((BuildContentManagerImpl)myBuildContentManager).finishBuildNotified(buildInfo.content); + onBuildFinish(buildInfo); } else { buildInfo.statusMessage = event.getMessage(); @@ -299,7 +338,9 @@ public abstract class AbstractViewManager implements BuildProgressListener, Disp ((BuildConsoleView)consoleView).onEvent(event); } else if ((consoleView instanceof ConsoleView)) { - ((ConsoleView)consoleView).print(event.getMessage(), ConsoleViewContentType.NORMAL_OUTPUT); + ((ConsoleView)consoleView).print(event.getMessage(), ((OutputBuildEvent)event).isStdOut() + ? ConsoleViewContentType.NORMAL_OUTPUT + : ConsoleViewContentType.ERROR_OUTPUT); } } else { @@ -352,8 +393,9 @@ public abstract class AbstractViewManager implements BuildProgressListener, Disp myContent = new ContentImpl(consoleComponent, getViewName(), true); myContent.setCloseable(false); + Icon contentIcon = getContentIcon(); + myContent.setIcon(contentIcon); myBuildContentManager.addContent(myContent); - myBuildContentManager.setSelectedContent(myContent); List postponedRunnables = new ArrayList<>(myPostponedRunnables); myPostponedRunnables.clear(); @@ -372,6 +414,21 @@ public abstract class AbstractViewManager implements BuildProgressListener, Disp } } + @Nullable + protected Icon getContentIcon() { + return null; + } + + protected void onBuildStart(BuildDescriptor buildDescriptor) { + } + + protected void onBuildFinish(BuildDescriptor buildDescriptor) { + BuildInfo buildInfo = (BuildInfo)buildDescriptor; + if (buildInfo.result instanceof FailureResult) { + myBuildContentManager.setSelectedContent(buildInfo.content, true, true, true, null); + } + } + protected boolean isConsoleEnabledByDefault() { return false; } @@ -411,13 +468,20 @@ public abstract class AbstractViewManager implements BuildProgressListener, Disp } } - private static class BuildInfo { - Object id; - String title; + static class BuildInfo extends DefaultBuildDescriptor { String message; String statusMessage; long endTime = -1; EventResult result; + Content content; + public boolean activateToolWindowWhenAdded; + + public BuildInfo(@NotNull Object id, + @NotNull String title, + @NotNull String workingDir, + long startTime) { + super(id, title, workingDir, startTime); + } public Icon getIcon() { return getIcon(result); diff --git a/java/compiler/impl/src/com/intellij/build/BuildContentManager.java b/java/compiler/impl/src/com/intellij/build/BuildContentManager.java index 9b7c4ce5ac8d..a6ccf8cfd44f 100644 --- a/java/compiler/impl/src/com/intellij/build/BuildContentManager.java +++ b/java/compiler/impl/src/com/intellij/build/BuildContentManager.java @@ -16,6 +16,7 @@ package com.intellij.build; import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.ActionCallback; import com.intellij.ui.content.Content; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -32,14 +33,15 @@ public interface BuildContentManager { void removeContent(final Content content); - void setSelectedContent(final Content content); - - void selectContent(final String tabName); - Content addTabbedContent(@NotNull JComponent contentComponent, @NotNull String groupPrefix, @NotNull String tabName, - boolean select, @Nullable Icon icon, @Nullable Disposable childDisposable); + + ActionCallback setSelectedContent(Content content, + boolean requestFocus, + boolean forcedFocus, + boolean activate, + Runnable activationCallback); } diff --git a/java/compiler/impl/src/com/intellij/build/BuildContentManagerImpl.java b/java/compiler/impl/src/com/intellij/build/BuildContentManagerImpl.java index 085fa71ed0f2..c275a7fa72a1 100644 --- a/java/compiler/impl/src/com/intellij/build/BuildContentManagerImpl.java +++ b/java/compiler/impl/src/com/intellij/build/BuildContentManagerImpl.java @@ -18,8 +18,10 @@ package com.intellij.build; import com.intellij.execution.runners.ExecutionUtil; import com.intellij.icons.AllIcons; import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; +import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Pair; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; @@ -51,6 +53,7 @@ public class BuildContentManagerImpl implements BuildContentManager { public static final String Build = "Build"; public static final String Sync = "Sync"; private static final String[] ourPresetOrder = {Build, Sync}; + private Project myProject; private ToolWindow myToolWindow; private final List myPostponedRunnables = new ArrayList<>(); private Map> liveContentsMap = ContainerUtil.newConcurrentMap(); @@ -60,6 +63,7 @@ public class BuildContentManagerImpl implements BuildContentManager { } private void init(Project project) { + myProject = project; final Runnable runnable = () -> { ToolWindow toolWindow = ToolWindowManager.getInstance(project) .registerToolWindow(ToolWindowId.BUILD, true, ToolWindowAnchor.BOTTOM, project, true); @@ -122,26 +126,35 @@ public class BuildContentManagerImpl implements BuildContentManager { for (Content existingContent : existingContents) { existingContent.setDisplayName(existingContent.getTabName()); } - Content firstContent = contentManager.getContent(0); - assert firstContent != null; - if (!Build.equals(firstContent.getTabName())) { - if (contentManager.getContentCount() > 1) { - setIdLabelHidden(false); - } - else { - // we are going to adjust display name, so we need to ensure tab name is not retrieved based on display name - content.setTabName(content.getTabName()); - content.setDisplayName(Build + ": " + content.getTabName()); - } + String tabName = content.getTabName(); + updateTabDisplayName(content, tabName); + }); + } + + public void updateTabDisplayName(Content content, String tabName) { + String displayName; + ContentManager contentManager = myToolWindow.getContentManager(); + Content firstContent = contentManager.getContent(0); + assert firstContent != null; + if (!Build.equals(firstContent.getTabName())) { + if (contentManager.getContentCount() > 1) { + setIdLabelHidden(false); + displayName = tabName; } else { - setIdLabelHidden(true); + displayName = Build + ": " + tabName; } + } + else { + displayName = tabName; + setIdLabelHidden(true); + } - if (contentManager.getContentCount() == 1) { - myToolWindow.show(null); - } - }); + if (!displayName.equals(content.getDisplayName())) { + // we are going to adjust display name, so we need to ensure tab name is not retrieved based on display name + content.setTabName(tabName); + content.setDisplayName(displayName); + } } @Override @@ -153,30 +166,27 @@ public class BuildContentManagerImpl implements BuildContentManager { } @Override - public void setSelectedContent(Content content) { - myToolWindow.getContentManager().setSelectedContent(content); - } - - @Override - public void selectContent(String tabName) { - ContentManager contentManager = myToolWindow.getContentManager(); - for (Content content : contentManager.getContents()) { - if (content.getDisplayName().equals(tabName)) { - contentManager.setSelectedContent(content, false); - break; - } + public ActionCallback setSelectedContent(Content content, + boolean requestFocus, + boolean forcedFocus, + boolean activate, + Runnable activationCallback) { + ActionCallback callback = myToolWindow.getContentManager().setSelectedContent(content, requestFocus, forcedFocus, false); + if (activate) { + ApplicationManager.getApplication().invokeLater( + () -> myToolWindow.activate(activationCallback, requestFocus, requestFocus), myProject.getDisposed()); } + return callback; } @Override public Content addTabbedContent(@NotNull JComponent contentComponent, @NotNull String groupPrefix, @NotNull String tabName, - boolean select, @Nullable Icon icon, @Nullable Disposable childDisposable) { ContentManager contentManager = myToolWindow.getContentManager(); - ContentUtilEx.addTabbedContent(contentManager, contentComponent, groupPrefix, tabName, select, childDisposable); + ContentUtilEx.addTabbedContent(contentManager, contentComponent, groupPrefix, tabName, false, childDisposable); Content content = contentManager.findContent(getFullName(groupPrefix, tabName)); if (icon != null) { TabbedContent tabbedContent = ContentUtilEx.findTabbedContent(contentManager, groupPrefix); @@ -191,14 +201,18 @@ public class BuildContentManagerImpl implements BuildContentManager { public void startBuildNotified(Content content) { Pair pair = liveContentsMap.computeIfAbsent(content, c -> Pair.pair(c.getIcon(), new AtomicInteger(0))); pair.second.incrementAndGet(); - content.setIcon(ExecutionUtil.getLiveIndicator(pair.first)); - myToolWindow.setIcon(ExecutionUtil.getLiveIndicator(AllIcons.Actions.Compile)); content.putUserData(ToolWindow.SHOW_CONTENT_ICON, Boolean.TRUE); + content.setIcon(ExecutionUtil.getLiveIndicator(pair.first)); + JComponent component = content.getComponent(); + if (component != null) { + component.invalidate(); + } + myToolWindow.setIcon(ExecutionUtil.getLiveIndicator(AllIcons.Actions.Compile)); } public void finishBuildNotified(Content content) { Pair pair = liveContentsMap.get(content); - if (pair.second.decrementAndGet() == 0) { + if (pair != null && pair.second.decrementAndGet() == 0) { content.setIcon(pair.first); if (pair.first == null) { content.putUserData(ToolWindow.SHOW_CONTENT_ICON, Boolean.FALSE); diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangesSelection.java b/java/compiler/impl/src/com/intellij/build/BuildDescriptor.java similarity index 58% rename from platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangesSelection.java rename to java/compiler/impl/src/com/intellij/build/BuildDescriptor.java index b48c1e25a9fd..249d148e38d0 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangesSelection.java +++ b/java/compiler/impl/src/com/intellij/build/BuildDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,27 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.openapi.vcs.changes; +package com.intellij.build; import org.jetbrains.annotations.NotNull; -import java.util.List; - -public class ChangesSelection { - @NotNull private final List myChanges; - private final int myIndex; - - public ChangesSelection(@NotNull List changes, int index) { - myChanges = changes; - myIndex = index; - } +/** + * @author Vladislav.Soroka + */ +public interface BuildDescriptor { + @NotNull + Object getId(); @NotNull - public List getChanges() { - return myChanges; - } + String getTitle(); - public int getIndex() { - return myIndex; - } + @NotNull + String getWorkingDir(); + + long getStartTime(); } diff --git a/java/compiler/impl/src/com/intellij/build/BuildTextConsoleView.java b/java/compiler/impl/src/com/intellij/build/BuildTextConsoleView.java index 1e7cbf3c2774..781db089b337 100644 --- a/java/compiler/impl/src/com/intellij/build/BuildTextConsoleView.java +++ b/java/compiler/impl/src/com/intellij/build/BuildTextConsoleView.java @@ -16,6 +16,7 @@ package com.intellij.build; import com.intellij.build.events.BuildEvent; +import com.intellij.build.events.OutputBuildEvent; import com.intellij.execution.impl.ConsoleViewImpl; import com.intellij.execution.process.AnsiEscapeDecoder; import com.intellij.execution.process.ProcessOutputTypes; @@ -40,7 +41,9 @@ public class BuildTextConsoleView extends ConsoleViewImpl implements BuildConsol @Override public void onEvent(BuildEvent event) { - myAnsiEscapeDecoder.escapeText(event.getMessage(), ProcessOutputTypes.STDOUT, this); + Key outputType = event instanceof OutputBuildEvent && !((OutputBuildEvent)event).isStdOut() + ? ProcessOutputTypes.STDERR : ProcessOutputTypes.STDOUT; + myAnsiEscapeDecoder.escapeText(event.getMessage(), outputType, this); } @Override diff --git a/java/compiler/impl/src/com/intellij/build/BuildTreeConsoleView.java b/java/compiler/impl/src/com/intellij/build/BuildTreeConsoleView.java index 834efb3f23d6..08bafde02812 100644 --- a/java/compiler/impl/src/com/intellij/build/BuildTreeConsoleView.java +++ b/java/compiler/impl/src/com/intellij/build/BuildTreeConsoleView.java @@ -45,6 +45,7 @@ import com.intellij.ui.treeStructure.treetable.TreeTableTree; import com.intellij.util.IJSwingUtilities; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; @@ -259,7 +260,7 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon @Override public JComponent getPreferredFocusableComponent() { - return null; + return myBuilder.getTree(); } @Override @@ -326,6 +327,10 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon myBuilder.queueUpdateFrom(currentNode, false, false); if (event instanceof FinishBuildEvent) { + String aHint = event.getHint(); + String time = DateFormatUtil.formatDateTime(event.getEventTime()); + aHint = aHint == null ? " at " + time : aHint + " at " + time; + currentNode.setHint(aHint); myProgressAnimator.stopMovie(); updateTimeColumnWidth(myTimeColumnWidth); if (myDetailsHandler.myExecutionNode == null) { diff --git a/java/compiler/impl/src/com/intellij/build/CompositeView.java b/java/compiler/impl/src/com/intellij/build/CompositeView.java index 8d1527437e81..65bea7992ecd 100644 --- a/java/compiler/impl/src/com/intellij/build/CompositeView.java +++ b/java/compiler/impl/src/com/intellij/build/CompositeView.java @@ -82,7 +82,7 @@ public class CompositeView { - IdeFocusManager.getGlobalInstance().requestFocus(getView(primary).getComponent(), true); + IdeFocusManager.getGlobalInstance().requestFocus(getView(primary).getPreferredFocusableComponent(), true); }); myPrimary = primary; } diff --git a/java/compiler/impl/src/com/intellij/build/DebugTasksViewManager.java b/java/compiler/impl/src/com/intellij/build/DebugTasksViewManager.java new file mode 100644 index 000000000000..cfb307df5cdc --- /dev/null +++ b/java/compiler/impl/src/com/intellij/build/DebugTasksViewManager.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2017 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.build; + +import com.intellij.openapi.project.Project; + +/** + * @author Vladislav.Soroka + */ +public class DebugTasksViewManager extends TasksViewManager { + public DebugTasksViewManager(Project project, BuildContentManager buildContentManager) { + super(project, buildContentManager); + } + + @Override + public String getViewName() { + return "Debug"; + } +} diff --git a/java/compiler/impl/src/com/intellij/build/DefaultBuildDescriptor.java b/java/compiler/impl/src/com/intellij/build/DefaultBuildDescriptor.java new file mode 100644 index 000000000000..40932df7f53b --- /dev/null +++ b/java/compiler/impl/src/com/intellij/build/DefaultBuildDescriptor.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2017 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.build; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Vladislav.Soroka + */ +public class DefaultBuildDescriptor implements BuildDescriptor { + + private final Object myId; + private final String myTitle; + private final String myWorkingDir; + private final long myStartTime; + + public DefaultBuildDescriptor(@NotNull Object id, @NotNull String title, @NotNull String workingDir, long startTime) { + myId = id; + myTitle = title; + myWorkingDir = workingDir; + myStartTime = startTime; + } + + + @NotNull + @Override + public Object getId() { + return myId; + } + + @NotNull + @Override + public String getTitle() { + return myTitle; + } + + @NotNull + @Override + public String getWorkingDir() { + return myWorkingDir; + } + + @Override + public long getStartTime() { + return myStartTime; + } +} diff --git a/java/compiler/impl/src/com/intellij/build/RunTasksViewManager.java b/java/compiler/impl/src/com/intellij/build/RunTasksViewManager.java new file mode 100644 index 000000000000..77bc83ea0072 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/build/RunTasksViewManager.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2017 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.build; + +import com.intellij.openapi.project.Project; + +/** + * @author Vladislav.Soroka + */ +public class RunTasksViewManager extends TasksViewManager { + public RunTasksViewManager(Project project, BuildContentManager buildContentManager) { + super(project, buildContentManager); + } + + @Override + public String getViewName() { + return "Run"; + } +} diff --git a/java/compiler/impl/src/com/intellij/build/SyncViewManager.java b/java/compiler/impl/src/com/intellij/build/SyncViewManager.java index 72933a1b452f..5ae784c560f8 100644 --- a/java/compiler/impl/src/com/intellij/build/SyncViewManager.java +++ b/java/compiler/impl/src/com/intellij/build/SyncViewManager.java @@ -15,6 +15,7 @@ */ package com.intellij.build; +import com.intellij.build.events.FailureResult; import com.intellij.openapi.project.Project; /** @@ -29,4 +30,13 @@ public class SyncViewManager extends AbstractViewManager { public String getViewName() { return "Sync"; } + + @Override + protected void onBuildFinish(BuildDescriptor buildDescriptor) { + BuildInfo buildInfo = (BuildInfo)buildDescriptor; + if (buildInfo.result instanceof FailureResult) { + boolean activate = buildInfo.activateToolWindowWhenAdded; + myBuildContentManager.setSelectedContent(buildInfo.content, activate, activate, activate, null); + } + } } \ No newline at end of file diff --git a/java/compiler/impl/src/com/intellij/build/TasksViewManager.java b/java/compiler/impl/src/com/intellij/build/TasksViewManager.java index 07cb24e29c79..67b0677e508c 100644 --- a/java/compiler/impl/src/com/intellij/build/TasksViewManager.java +++ b/java/compiler/impl/src/com/intellij/build/TasksViewManager.java @@ -15,24 +15,41 @@ */ package com.intellij.build; +import com.intellij.icons.AllIcons; import com.intellij.openapi.project.Project; +import com.intellij.ui.content.Content; + +import javax.swing.*; +import java.util.Map; /** * @author Vladislav.Soroka */ -public class TasksViewManager extends AbstractViewManager { +public abstract class TasksViewManager extends AbstractViewManager { public TasksViewManager(Project project, BuildContentManager buildContentManager) { super(project, buildContentManager); } + @Override - public String getViewName() { - return "Run"; + protected void onBuildStart(BuildDescriptor buildDescriptor) { + if (!isTabbedView()) { + BuildInfo buildInfo = (BuildInfo)buildDescriptor; + Content content = buildInfo.content; + Map buildsMap = getBuildsMap(); + String tabName = buildsMap.size() > 1 ? getViewName() : getViewName() + ": " + buildInfo.getTitle(); + ((BuildContentManagerImpl)myBuildContentManager).updateTabDisplayName(content, tabName); + } } @Override protected boolean isTabbedView() { - return true; + return false; + } + + @Override + protected Icon getContentIcon() { + return AllIcons.CodeStyle.Gear; } @Override diff --git a/java/compiler/impl/src/com/intellij/build/events/OutputBuildEvent.java b/java/compiler/impl/src/com/intellij/build/events/OutputBuildEvent.java index c35319949fb6..94cdccd37e01 100644 --- a/java/compiler/impl/src/com/intellij/build/events/OutputBuildEvent.java +++ b/java/compiler/impl/src/com/intellij/build/events/OutputBuildEvent.java @@ -16,11 +16,15 @@ package com.intellij.build.events; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; /** * @author Vladislav.Soroka */ @ApiStatus.Experimental public interface OutputBuildEvent { + @NotNull + String getMessage(); + boolean isStdOut(); } diff --git a/java/compiler/impl/src/com/intellij/build/events/StartBuildEvent.java b/java/compiler/impl/src/com/intellij/build/events/StartBuildEvent.java index 90bd9b5e494c..f910d44487a1 100644 --- a/java/compiler/impl/src/com/intellij/build/events/StartBuildEvent.java +++ b/java/compiler/impl/src/com/intellij/build/events/StartBuildEvent.java @@ -15,6 +15,7 @@ */ package com.intellij.build.events; +import com.intellij.execution.filters.Filter; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.ui.ConsoleView; @@ -34,6 +35,9 @@ import java.util.function.Supplier; public interface StartBuildEvent extends StartEvent { String getBuildTitle(); + @NotNull + String getWorkingDir(); + @Nullable ProcessHandler getProcessHandler(); @@ -43,6 +47,9 @@ public interface StartBuildEvent extends StartEvent { @NotNull AnAction[] getRestartActions(); + @NotNull + Filter[] getExecutionFilters(); + @Nullable Supplier getContentDescriptorSupplier(); diff --git a/java/compiler/impl/src/com/intellij/build/events/impl/OutputBuildEventImpl.java b/java/compiler/impl/src/com/intellij/build/events/impl/OutputBuildEventImpl.java index 76a64a3d0fcb..291b818cc397 100644 --- a/java/compiler/impl/src/com/intellij/build/events/impl/OutputBuildEventImpl.java +++ b/java/compiler/impl/src/com/intellij/build/events/impl/OutputBuildEventImpl.java @@ -23,11 +23,19 @@ import org.jetbrains.annotations.Nullable; * @author Vladislav.Soroka */ public class OutputBuildEventImpl extends AbstractBuildEvent implements OutputBuildEvent { + private boolean myStdOut; + public OutputBuildEventImpl(@Nullable Object parentId, @NotNull String message, boolean stdOut) { this(new Object(), parentId, message, stdOut); } public OutputBuildEventImpl(@NotNull Object eventId, @Nullable Object parentId, @NotNull String message, boolean stdOut) { super(eventId, parentId, -1, message); + myStdOut = stdOut; + } + + @Override + public boolean isStdOut() { + return myStdOut; } } diff --git a/java/compiler/impl/src/com/intellij/build/events/impl/StartBuildEventImpl.java b/java/compiler/impl/src/com/intellij/build/events/impl/StartBuildEventImpl.java index b0eaa1343a76..6eb8a881da39 100644 --- a/java/compiler/impl/src/com/intellij/build/events/impl/StartBuildEventImpl.java +++ b/java/compiler/impl/src/com/intellij/build/events/impl/StartBuildEventImpl.java @@ -15,7 +15,9 @@ */ package com.intellij.build.events.impl; +import com.intellij.build.BuildDescriptor; import com.intellij.build.events.StartBuildEvent; +import com.intellij.execution.filters.Filter; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.ui.ConsoleView; @@ -36,22 +38,23 @@ import java.util.function.Supplier; public class StartBuildEventImpl extends StartEventImpl implements StartBuildEvent { private final String myBuildTitle; + private final String myWorkingDir; @Nullable private ProcessHandler myProcessHandler; private Consumer myAttachedConsoleConsumer; @NotNull private List myRestartActions = new SmartList<>(); + @NotNull + private List myFilters = new SmartList<>(); @Nullable private ExecutionEnvironment myExecutionEnvironment; @Nullable private Supplier myContentDescriptorSupplier; - public StartBuildEventImpl(@NotNull Object eventId, - @NotNull String buildTitle, - long eventTime, - @NotNull String message) { - super(eventId, null, eventTime, message); - myBuildTitle = buildTitle; + public StartBuildEventImpl(@NotNull BuildDescriptor descriptor, @NotNull String message) { + super(descriptor.getId(), null, descriptor.getStartTime(), message); + myBuildTitle = descriptor.getTitle(); + myWorkingDir = descriptor.getWorkingDir(); } @Override @@ -59,6 +62,12 @@ public class StartBuildEventImpl extends StartEventImpl implements StartBuildEve return myBuildTitle; } + @NotNull + @Override + public String getWorkingDir() { + return myWorkingDir; + } + @Nullable @Override public ProcessHandler getProcessHandler() { @@ -77,6 +86,12 @@ public class StartBuildEventImpl extends StartEventImpl implements StartBuildEve return myRestartActions.toArray(new AnAction[myRestartActions.size()]); } + @NotNull + @Override + public Filter[] getExecutionFilters() { + return myFilters.toArray(new Filter[myFilters.size()]); + } + @Nullable @Override public Supplier getContentDescriptorSupplier() { @@ -96,7 +111,7 @@ public class StartBuildEventImpl extends StartEventImpl implements StartBuildEve return this; } - public StartBuildEventImpl withRestartAction(@Nullable AnAction anAction) { + public StartBuildEventImpl withRestartAction(@NotNull AnAction anAction) { myRestartActions.add(anAction); return this; } @@ -115,4 +130,14 @@ public class StartBuildEventImpl extends StartEventImpl implements StartBuildEve myContentDescriptorSupplier = contentDescriptorSupplier; return this; } + + public StartBuildEventImpl withExecutionFilter(@NotNull Filter filter) { + myFilters.add(filter); + return this; + } + + public StartBuildEventImpl withExecutionFilters(Filter... filters) { + myFilters.addAll(Arrays.asList(filters)); + return this; + } } diff --git a/java/compiler/impl/src/com/intellij/build/internal/DummyBuildContentManager.java b/java/compiler/impl/src/com/intellij/build/internal/DummyBuildContentManager.java index 49a8b78e7a5c..0647a4c9ca87 100644 --- a/java/compiler/impl/src/com/intellij/build/internal/DummyBuildContentManager.java +++ b/java/compiler/impl/src/com/intellij/build/internal/DummyBuildContentManager.java @@ -17,6 +17,7 @@ package com.intellij.build.internal; import com.intellij.build.BuildContentManager; import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.ActionCallback; import com.intellij.ui.content.Content; import com.intellij.ui.content.impl.ContentImpl; import org.jetbrains.annotations.NotNull; @@ -37,18 +38,18 @@ public class DummyBuildContentManager implements BuildContentManager { } @Override - public void setSelectedContent(Content content) { - } - - @Override - public void selectContent(String tabName) { + public ActionCallback setSelectedContent(Content content, + boolean requestFocus, + boolean forcedFocus, + boolean activate, + Runnable activationCallback) { + return null; } @Override public Content addTabbedContent(@NotNull JComponent contentComponent, @NotNull String groupPrefix, @NotNull String tabName, - boolean select, @Nullable Icon icon, @Nullable Disposable childDisposable) { return new ContentImpl(contentComponent, tabName, false); diff --git a/java/compiler/impl/src/com/intellij/build/internal/DummyTasksViewManager.java b/java/compiler/impl/src/com/intellij/build/internal/DummyTasksViewManager.java index 078dfcc4ba76..ed904cdac95d 100644 --- a/java/compiler/impl/src/com/intellij/build/internal/DummyTasksViewManager.java +++ b/java/compiler/impl/src/com/intellij/build/internal/DummyTasksViewManager.java @@ -16,7 +16,7 @@ package com.intellij.build.internal; import com.intellij.build.BuildContentManager; -import com.intellij.build.SyncViewManager; +import com.intellij.build.TasksViewManager; import com.intellij.build.events.BuildEvent; import com.intellij.build.events.FinishBuildEvent; import com.intellij.openapi.project.Project; @@ -24,11 +24,16 @@ import com.intellij.openapi.project.Project; /** * @author Vladislav.Soroka */ -public class DummyTasksViewManager extends SyncViewManager { +public class DummyTasksViewManager extends TasksViewManager { public DummyTasksViewManager(Project project, BuildContentManager buildContentManager) { super(project, buildContentManager); } + @Override + protected String getViewName() { + return "Tasks"; + } + @Override public void onEvent(BuildEvent event) { if(event instanceof FinishBuildEvent) { diff --git a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/context/ChainCompletionContext.java b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/context/ChainCompletionContext.java index 43b66f10df3a..b1f590a5cd4b 100644 --- a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/context/ChainCompletionContext.java +++ b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/context/ChainCompletionContext.java @@ -26,10 +26,7 @@ import com.intellij.psi.scope.BaseScopeProcessor; import com.intellij.psi.scope.ElementClassHint; import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.ClassUtil; -import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.*; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.FactoryMap; @@ -235,7 +232,7 @@ public class ChainCompletionContext { @Override public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) { - if ((!(element instanceof PsiMethod) || PropertyUtil.isSimplePropertyAccessor((PsiMethod)element)) && + if ((!(element instanceof PsiMethod) || PropertyUtilBase.isSimplePropertyAccessor((PsiMethod)element)) && (!(element instanceof PsiVariable) || !myExcludedVariables.contains(element)) && (!(element instanceof PsiMember) || myResolveHelper.isAccessible((PsiMember)element, myPlace, null))) { PsiType type = getType(element); diff --git a/java/compiler/impl/src/com/intellij/compiler/inspection/FrequentlyUsedInheritorInspection.java b/java/compiler/impl/src/com/intellij/compiler/inspection/FrequentlyUsedInheritorInspection.java index e7339f255686..24350c196642 100644 --- a/java/compiler/impl/src/com/intellij/compiler/inspection/FrequentlyUsedInheritorInspection.java +++ b/java/compiler/impl/src/com/intellij/compiler/inspection/FrequentlyUsedInheritorInspection.java @@ -27,7 +27,6 @@ import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.psi.impl.java.stubs.index.JavaFullClassNameIndex; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; import com.intellij.util.SystemProperties; @@ -179,17 +178,14 @@ public class FrequentlyUsedInheritorInspection extends BaseJavaLocalInspectionTo .filter(Objects::nonNull) .map(defAndCount -> { String name = compilerRefService.getName(defAndCount.myDef.getName()); - PsiClass inheritor = - JavaFullClassNameIndex.getInstance().get(name.hashCode(), project, searchScope).stream() - .filter(cls -> name.equals(cls.getQualifiedName())) - .collect(MoreCollectors.onlyOne()) - .orElse(null); - - if (inheritor == null || !inheritor.isInheritor(aClass, false)) { - return null; + PsiClass[] inheritors = JavaPsiFacade.getInstance(project).findClasses(name, searchScope); + if (inheritors.length == 1) { + PsiClass inheritor = inheritors[0]; + if (inheritor.isInheritor(aClass, false)) { + return new ClassAndInheritorCount(inheritor, defAndCount.myDef, defAndCount.inheritorCount); + } } - - return new ClassAndInheritorCount(inheritor, defAndCount.myDef, defAndCount.inheritorCount); + return null; }) .filter(Objects::nonNull) .collect(Collectors.toList()); diff --git a/java/compiler/impl/src/com/intellij/compiler/options/ValidationConfigurable.java b/java/compiler/impl/src/com/intellij/compiler/options/ValidationConfigurable.java index 23f5255cf88b..4ce292084b14 100644 --- a/java/compiler/impl/src/com/intellij/compiler/options/ValidationConfigurable.java +++ b/java/compiler/impl/src/com/intellij/compiler/options/ValidationConfigurable.java @@ -36,6 +36,7 @@ import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.uiDesigner.core.GridConstraints; import com.intellij.util.NullableFunction; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; @@ -148,8 +149,7 @@ public class ValidationConfigurable implements SearchableConfigurable, Configura private List getValidators() { final CompilerManager compilerManager = CompilerManager.getInstance(myProject); - final List validators = new ArrayList<>(); - validators.addAll(Arrays.asList(compilerManager.getCompilers(Validator.class))); + final List validators = new SmartList<>(compilerManager.getCompilers(Validator.class)); for (GenericCompiler compiler : compilerManager.getCompilers(GenericCompiler.class)) { if (compiler.getOrderPlace() == GenericCompiler.CompileOrderPlace.VALIDATING) { validators.add(compiler); diff --git a/java/compiler/impl/src/com/intellij/task/impl/InternalProjectTaskRunner.java b/java/compiler/impl/src/com/intellij/task/impl/InternalProjectTaskRunner.java index 20772d6472b9..a58b3dffac73 100644 --- a/java/compiler/impl/src/com/intellij/task/impl/InternalProjectTaskRunner.java +++ b/java/compiler/impl/src/com/intellij/task/impl/InternalProjectTaskRunner.java @@ -71,13 +71,6 @@ public class InternalProjectTaskRunner extends ProjectTaskRunner { return true; } - @Override - public ExecutionEnvironment createExecutionEnvironment(@NotNull Project project, - @NotNull ExecuteRunConfigurationTask task, - @Nullable Executor executor) { - return null; - } - public static Map, List> groupBy(@NotNull Collection tasks) { return tasks.stream().collect(Collectors.groupingBy(o -> { if (o instanceof ModuleFilesBuildTask) return ModuleFilesBuildTask.class; diff --git a/java/compiler/openapi/src/com/intellij/task/ProjectTaskRunner.java b/java/compiler/openapi/src/com/intellij/task/ProjectTaskRunner.java index b3dc313504e9..e6a4c011a969 100644 --- a/java/compiler/openapi/src/com/intellij/task/ProjectTaskRunner.java +++ b/java/compiler/openapi/src/com/intellij/task/ProjectTaskRunner.java @@ -47,7 +47,10 @@ public abstract class ProjectTaskRunner { public abstract boolean canRun(@NotNull ProjectTask projectTask); - public abstract ExecutionEnvironment createExecutionEnvironment(@NotNull Project project, - @NotNull ExecuteRunConfigurationTask task, - @Nullable Executor executor); + @Nullable + public ExecutionEnvironment createExecutionEnvironment(@NotNull Project project, + @NotNull ExecuteRunConfigurationTask task, + @Nullable Executor executor) { + return null; + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaAttachDebuggerProvider.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaAttachDebuggerProvider.java index 7c71ff4d6f38..af3229b412ad 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaAttachDebuggerProvider.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaAttachDebuggerProvider.java @@ -15,6 +15,7 @@ */ package com.intellij.debugger.engine; +import com.intellij.debugger.impl.DebuggerManagerImpl; import com.intellij.execution.ProgramRunnerUtil; import com.intellij.execution.RunManager; import com.intellij.execution.RunnerAndConfigurationSettings; @@ -29,6 +30,7 @@ import com.intellij.openapi.util.UserDataHolder; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.ReflectionUtil; +import com.intellij.util.execution.ParametersListUtil; import com.intellij.xdebugger.attach.XDefaultLocalAttachGroup; import com.intellij.xdebugger.attach.XLocalAttachDebugger; import com.intellij.xdebugger.attach.XLocalAttachDebuggerProvider; @@ -71,7 +73,8 @@ public class JavaAttachDebuggerProvider implements XLocalAttachDebuggerProvider .createRunConfiguration(name, Objects.requireNonNull(ConfigurationTypeUtil.findConfigurationType("Remote")).getConfigurationFactories()[0]); RunConfiguration remoteConfiguration = runSettings.getConfiguration(); - ReflectionUtil.setField(remoteConfiguration.getClass(), remoteConfiguration, String.class, "HOST", address.first); + String host = address.first != null && !"*".equals(address.first) ? address.first : DebuggerManagerImpl.LOCALHOST_ADDRESS_FALLBACK; + ReflectionUtil.setField(remoteConfiguration.getClass(), remoteConfiguration, String.class, "HOST", host); ReflectionUtil.setField(remoteConfiguration.getClass(), remoteConfiguration, String.class, "PORT", String.valueOf(address.second)); ReflectionUtil.setField(remoteConfiguration.getClass(), remoteConfiguration, boolean.class, "USE_SOCKET_TRANSPORT", true); ReflectionUtil.setField(remoteConfiguration.getClass(), remoteConfiguration, boolean.class, "SERVER_MODE", false); @@ -124,6 +127,6 @@ public class JavaAttachDebuggerProvider implements XLocalAttachDebuggerProvider } private static Pair getAttachAddress(ProcessInfo processInfo) { - return DebugAttachDetector.getAttachAddress(StringUtil.split(processInfo.getCommandLine(), " ")); + return DebugAttachDetector.getAttachAddress(ParametersListUtil.parse(processInfo.getCommandLine())); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java index 90422220c48a..488e5c4e3174 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java @@ -70,6 +70,7 @@ import java.util.stream.Stream; @State(name = "DebuggerManager", storages = {@Storage(StoragePathMacros.WORKSPACE_FILE)}) public class DebuggerManagerImpl extends DebuggerManagerEx implements PersistentStateComponent { private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.DebuggerManagerImpl"); + public static final String LOCALHOST_ADDRESS_FALLBACK = "127.0.0.1"; private final Project myProject; private final HashMap mySessions = new HashMap<>(); @@ -449,7 +450,7 @@ public class DebuggerManagerImpl extends DebuggerManagerEx implements Persistent } final TransportServiceWrapper transportService = TransportServiceWrapper.getTransportService(useSockets); - final String debugAddress = debuggerInServerMode && useSockets ? "127.0.0.1:" + address : address; + final String debugAddress = debuggerInServerMode && useSockets ? LOCALHOST_ADDRESS_FALLBACK + ":" + address : address; String debuggeeRunProperties = "transport=" + transportService.transportId() + ",address=" + debugAddress; if (debuggerInServerMode) { debuggeeRunProperties += ",suspend=y,server=n"; @@ -498,7 +499,7 @@ public class DebuggerManagerImpl extends DebuggerManagerEx implements Persistent parameters.getVMParametersList().replaceOrPrepend("-classic", forceClassicVM ? "-classic" : ""); }); - return new RemoteConnection(useSockets, "127.0.0.1", address, debuggerInServerMode); + return new RemoteConnection(useSockets, LOCALHOST_ADDRESS_FALLBACK, address, debuggerInServerMode); } private static boolean shouldForceNoJIT(Sdk jdk) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java index 370819daa7d1..b2c0ed053d75 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java @@ -42,7 +42,6 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.psi.impl.java.stubs.index.JavaFullClassNameIndex; import com.intellij.psi.jsp.JspFile; import com.intellij.psi.search.EverythingGlobalScope; import com.intellij.psi.search.GlobalSearchScope; @@ -247,10 +246,10 @@ public class LineBreakpoint

extends Breakpoi final GlobalSearchScope scope = debugProcess.getSearchScope(); final boolean contains = scope.contains(breakpointFile); List files = ContainerUtil.map( - JavaFullClassNameIndex.getInstance().get(className.hashCode(), myProject, scope), + JavaPsiFacade.getInstance(myProject).findClasses(className, scope), aClass -> aClass.getContainingFile().getVirtualFile()); List allFiles = ContainerUtil.map( - JavaFullClassNameIndex.getInstance().get(className.hashCode(), myProject, new EverythingGlobalScope(myProject)), + JavaPsiFacade.getInstance(myProject).findClasses(className, new EverythingGlobalScope(myProject)), aClass -> aClass.getContainingFile().getVirtualFile()); final VirtualFile contentRoot = fileIndex.getContentRootForFile(breakpointFile); final Module module = fileIndex.getModuleForFile(breakpointFile); @@ -264,7 +263,7 @@ public class LineBreakpoint

extends Breakpoi "; all possible files are: " + allFiles ); } - + return false; } } @@ -357,7 +356,7 @@ public class LineBreakpoint

extends Breakpoi final int dotIndex = className.lastIndexOf("."); if (dotIndex >= 0 && !isFile) { packageName = className.substring(0, dotIndex); - className = className.substring(dotIndex + 1); + className = className.substring(dotIndex + 1); } if (totalTextLength != -1) { @@ -369,7 +368,7 @@ public class LineBreakpoint

extends Breakpoi } } } - + info.append(className); } if(hasMethodInfo) { diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/StepSequence.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/StepSequence.java index a58a9ada8aec..69163219ec28 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/StepSequence.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/StepSequence.java @@ -22,6 +22,7 @@ import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.roots.ui.configuration.ModulesProvider; import com.intellij.openapi.util.Pair; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NonNls; @@ -31,14 +32,14 @@ import org.jetbrains.annotations.Nullable; import java.util.*; public class StepSequence { - private final List myCommonSteps = new ArrayList<>(); + private final List myCommonSteps; private final List>> myCommonFinishingSteps = new ArrayList<>(); private final MultiMap mySpecificSteps = new MultiMap<>(); @NonNls private List myTypes = new ArrayList<>(); private List mySelectedSteps; public StepSequence(ModuleWizardStep... commonSteps) { - myCommonSteps.addAll(Arrays.asList(commonSteps)); + myCommonSteps = new SmartList<>(commonSteps); } public void addCommonStep(@NotNull ModuleWizardStep step){ diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java index cef3cc1ef0e3..ea3d73210855 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java @@ -34,6 +34,7 @@ import com.intellij.openapi.roots.ui.configuration.LibrarySourceRootDetectorUtil import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileVisitor; @@ -68,12 +69,16 @@ public class DefaultLibraryRootsComponentDescriptor extends LibraryRootsComponen @Override public List getRootDetectors() { List results = new ArrayList<>(); - results.add(new FileTypeBasedRootFilter(OrderRootType.CLASSES, false, StdFileTypes.CLASS, "classes")); - results.add(new FileTypeBasedRootFilter(OrderRootType.CLASSES, true, StdFileTypes.CLASS, "jar directory")); + results.add(new DescendentBasedRootFilter(OrderRootType.CLASSES, false, "classes", + file -> StdFileTypes.CLASS.equals(file.getFileType()) + //some libraries store native libraries inside their JAR files and unpack them dynamically so we should detect such JARs as classes roots + || file.getFileSystem() instanceof JarFileSystem && isNativeLibrary(file))); + results.add(DescendentBasedRootFilter.createFileTypeBasedFilter(OrderRootType.CLASSES, true, StdFileTypes.CLASS, "jar directory")); ContainerUtil.addAll(results, Extensions.getExtensions(LibrarySourceRootDetectorUtil.JAVA_SOURCE_ROOT_DETECTOR)); - results.add(new FileTypeBasedRootFilter(OrderRootType.SOURCES, true, StdFileTypes.JAVA, "source archive directory")); + results.add(DescendentBasedRootFilter.createFileTypeBasedFilter(OrderRootType.SOURCES, true, StdFileTypes.JAVA, "source archive directory")); results.add(new JavadocRootDetector()); - results.add(new AnnotationsRootFilter()); + results.add(new DescendentBasedRootFilter(AnnotationOrderRootType.getInstance(), false, "external annotations", + file -> ExternalAnnotationsManager.ANNOTATIONS_XML.equals(file.getName()))); results.add(new NativeLibraryRootFilter()); return results; } @@ -128,17 +133,6 @@ public class DefaultLibraryRootsComponentDescriptor extends LibraryRootsComponen } } - private static class AnnotationsRootFilter extends FileTypeBasedRootFilter { - private AnnotationsRootFilter() { - super(AnnotationOrderRootType.getInstance(), false, StdFileTypes.XML, "external annotations"); - } - - @Override - protected boolean isFileAccepted(VirtualFile virtualFile) { - return super.isFileAccepted(virtualFile) && virtualFile.getName().equals(ExternalAnnotationsManager.ANNOTATIONS_XML); - } - } - private static class NativeLibraryRootFilter extends RootDetector { private NativeLibraryRootFilter() { super(NativeLibraryOrderRootType.getInstance(), false, "native library location"); diff --git a/java/idea-ui/testSrc/com/intellij/openapi/roots/ui/configuration/libraryEditor/JavaLibraryRootsDetectionTest.kt b/java/idea-ui/testSrc/com/intellij/openapi/roots/ui/configuration/libraryEditor/JavaLibraryRootsDetectionTest.kt new file mode 100644 index 000000000000..3786241e3037 --- /dev/null +++ b/java/idea-ui/testSrc/com/intellij/openapi/roots/ui/configuration/libraryEditor/JavaLibraryRootsDetectionTest.kt @@ -0,0 +1,104 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.roots.ui.configuration.libraryEditor + +import com.intellij.openapi.fileTypes.StdFileTypes +import com.intellij.openapi.progress.EmptyProgressIndicator +import com.intellij.openapi.roots.NativeLibraryOrderRootType +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.roots.libraries.ui.impl.LibraryRootsDetectorImpl +import com.intellij.openapi.vfs.JarFileSystem +import com.intellij.testFramework.LightPlatformTestCase +import com.intellij.util.io.DirectoryContentBuilder +import com.intellij.util.io.directoryContent +import com.intellij.util.io.generateInVirtualTempDir + +/** + * @author nik + */ +class JavaLibraryRootsDetectionTest : LightPlatformTestCase() { + fun `test JAR with classes`() { + assertRootType(OrderRootType.CLASSES, false) { + zip("classes.jar") { + file("A.class") + } + } + } + + fun `test directory with classes`() { + assertRootType(OrderRootType.CLASSES, false) { + dir("classes") { + file("A.class") + } + } + } + + fun `test directory with sources`() { + assertRootType(OrderRootType.SOURCES, false) { + dir("src") { + file("A.java", "class A {}") + } + } + } + + fun `test JAR directory`() { + assertRootType(OrderRootType.CLASSES, true) { + dir("lib") { + zip("a.jar") { + file("A.class") + } + } + } + } + + fun `test sources zip directory`() { + assertRootType(OrderRootType.SOURCES, true) { + dir("lib") { + zip("src.zip") { + file("A.java", "class A {}") + } + } + } + } + + fun `test native library`() { + assertRootType(NativeLibraryOrderRootType.getInstance(), false) { + dir("lib") { + file("a.dll") + } + } + } + + fun `test native library in JAR`() { + assertRootType(OrderRootType.CLASSES, false) { + zip("a.jar") { + file("a.dll") + } + } + } + + private fun assertRootType(expectedType: OrderRootType, jarDirectory: Boolean, content: DirectoryContentBuilder.() -> Unit) { + val dir = directoryContent(content).generateInVirtualTempDir() + val detector = LibraryRootsDetectorImpl(DefaultLibraryRootsComponentDescriptor().rootDetectors) + val root = assertOneElement(dir.children.flatMap { file -> + val rootFile = if (file.fileType == StdFileTypes.ARCHIVE) JarFileSystem.getInstance().getJarRootForLocalFile(file)!! else file + detector.detectRoots(rootFile, EmptyProgressIndicator()) + }) + val type = assertOneElement(root.types) + assertEquals(expectedType, type.type) + assertEquals(jarDirectory, type.isJarDirectory) + } +} \ No newline at end of file diff --git a/java/idea-ui/testSrc/com/intellij/openapi/roots/ui/configuration/projectRoot/ConvertToRepositoryLibraryActionTest.kt b/java/idea-ui/testSrc/com/intellij/openapi/roots/ui/configuration/projectRoot/ConvertToRepositoryLibraryActionTest.kt index ce0c11d024f8..0b5fafbabed6 100644 --- a/java/idea-ui/testSrc/com/intellij/openapi/roots/ui/configuration/projectRoot/ConvertToRepositoryLibraryActionTest.kt +++ b/java/idea-ui/testSrc/com/intellij/openapi/roots/ui/configuration/projectRoot/ConvertToRepositoryLibraryActionTest.kt @@ -15,18 +15,72 @@ */ package com.intellij.openapi.roots.ui.configuration.projectRoot -import com.intellij.project.IntelliJProjectConfiguration +import com.intellij.openapi.vfs.JarFileSystem import com.intellij.testFramework.LightPlatformTestCase +import com.intellij.util.io.directoryContent +import com.intellij.util.io.generateInVirtualTempDir /** * @author nik */ class ConvertToRepositoryLibraryActionTest : LightPlatformTestCase() { - fun `test read Maven coordinates`() { - val file = IntelliJProjectConfiguration.getJarFromSingleJarProjectLibrary("commons-codec") - val coordinates = assertOneElement(ConvertToRepositoryLibraryActionBase.detectMavenCoordinates(arrayOf(file!!))) - assertEquals("commons-codec", coordinates.groupId) - assertEquals("commons-codec", coordinates.artifactId) - assertEquals("1.9", coordinates.version) + fun `test detect single coordinates`() { + val file = directoryContent { + zip("library.jar") { + dir("META-INF") { + dir("maven") { + dir("myGroupId") { + dir("myArtifactId") { + file("pom.properties", """ + |version=1.0 + |groupId=myGroupId + |artifactId=myArtifactId + """.trimMargin()) + } + } + } + } + } + }.generateInVirtualTempDir().findChild("library.jar")!! + val jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(file)!! + val coordinates = assertOneElement(ConvertToRepositoryLibraryActionBase.detectMavenCoordinates(arrayOf(jarRoot))) + assertEquals("myGroupId", coordinates.groupId) + assertEquals("myArtifactId", coordinates.artifactId) + assertEquals("1.0", coordinates.version) + } + + fun `test detect multiple coordinates`() { + val file = directoryContent { + zip("library2.jar") { + dir("META-INF") { + dir("maven") { + dir("myGroupId") { + dir("myArtifactId1") { + file("pom.properties", """ + |version=1.0 + |groupId=myGroupId + |artifactId=myArtifactId1 + """.trimMargin()) + } + dir("myArtifactId2") { + file("pom.properties", """ + |version=1.0 + |groupId=myGroupId + |artifactId=myArtifactId2 + """.trimMargin()) + } + } + } + } + } + }.generateInVirtualTempDir().findChild("library2.jar")!! + val jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(file)!! + val (coordinates1, coordinates2) = ConvertToRepositoryLibraryActionBase.detectMavenCoordinates(arrayOf(jarRoot)).sortedBy { it.artifactId } + assertEquals("myGroupId", coordinates1.groupId) + assertEquals("myArtifactId1", coordinates1.artifactId) + assertEquals("1.0", coordinates1.version) + assertEquals("myGroupId", coordinates2.groupId) + assertEquals("myArtifactId2", coordinates2.artifactId) + assertEquals("1.0", coordinates2.version) } } \ No newline at end of file diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/JavaSoftKeywordHighlighting.kt b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/JavaSoftKeywordHighlighting.kt index de77df2d9d58..171cff8d2934 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/JavaSoftKeywordHighlighting.kt +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/JavaSoftKeywordHighlighting.kt @@ -35,7 +35,9 @@ class JavaSoftKeywordHighlightingPassFactory(project: Project, registrar: TextEd } override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? { - val visit = file is PsiJavaFile && file.name == PsiJavaModule.MODULE_INFO_FILE && file.languageLevel.isAtLeast(LanguageLevel.JDK_1_9) + val visit = file is PsiJavaFile && + (file.name == PsiJavaModule.MODULE_INFO_FILE && file.languageLevel.isAtLeast(LanguageLevel.JDK_1_9) || + file.languageLevel.isAtLeast(LanguageLevel.JDK_X)) return if (visit) JavaSoftKeywordHighlightingPass(file as PsiJavaFile, editor.document) else null } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/UnusedSymbolUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/UnusedSymbolUtil.java index 376c4dd0db22..1a8b181e3cdd 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/UnusedSymbolUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/UnusedSymbolUtil.java @@ -34,6 +34,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiSearchHelper; import com.intellij.psi.search.SearchScope; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.usageView.UsageInfo; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; @@ -232,7 +233,7 @@ public class UnusedSymbolUtil { } if (member instanceof PsiMethod) { - String propertyName = PropertyUtil.getPropertyName(member); + String propertyName = PropertyUtilBase.getPropertyName(member); if (propertyName != null) { SearchScope fileScope = containingFile.getUseScope(); if (fileScope instanceof GlobalSearchScope && @@ -286,7 +287,7 @@ public class UnusedSymbolUtil { if (!(containingFile instanceof PsiJavaFile)) return true; // Groovy field can be referenced from Java by getter if (member instanceof PsiField) return false; //Java field cannot be referenced by anything but its name if (member instanceof PsiMethod) { - return PropertyUtil.isSimplePropertyAccessor((PsiMethod)member); //Java accessors can be referenced by field name from Groovy + return PropertyUtilBase.isSimplePropertyAccessor((PsiMethod)member); //Java accessors can be referenced by field name from Groovy } return false; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ErrorFixExtensionPoint.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ErrorFixExtensionPoint.java index 4ff7f77570b1..f1f3aa129676 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ErrorFixExtensionPoint.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ErrorFixExtensionPoint.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.openapi.extensions.AbstractExtensionPointBean; import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.psi.PsiElement; import com.intellij.util.xmlb.annotations.Attribute; import one.util.streamex.StreamEx; @@ -48,7 +49,13 @@ public class ErrorFixExtensionPoint extends AbstractExtensionPointBean { try { return findClass(implementationClass).asSubclass(IntentionAction.class).getConstructor(PsiElement.class).newInstance(context); } - catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException e) { + catch (InvocationTargetException e) { + if(e.getCause() instanceof ProcessCanceledException) { + throw ((ProcessCanceledException)e.getCause()); + } + throw new RuntimeException("Error instantiating quick-fix " + implementationClass + " (error code: " + errorCode + ")", e.getCause()); + } + catch (InstantiationException | IllegalAccessException | NoSuchMethodException | ClassNotFoundException e) { throw new RuntimeException("Error instantiating quick-fix " + implementationClass + " (error code: " + errorCode + ")", e); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 7a4ead47e763..5e10a8ee9915 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -3063,7 +3063,7 @@ public class HighlightUtil extends HighlightUtilBase { final PsiClass containingClass = psiField.getContainingClass(); if (containingClass != null) { if (PsiUtil.isOnAssignmentLeftHand((PsiExpression)place)) { - final PsiMethod setterPrototype = PropertyUtil.generateSetterPrototype(psiField); + final PsiMethod setterPrototype = PropertyUtilBase.generateSetterPrototype(psiField); final PsiMethod setter = containingClass.findMethodBySignature(setterPrototype, true); if (setter != null && PsiUtil.isAccessible(setter, place, accessObjectClass)) { final PsiElement element = PsiTreeUtil.skipParentsOfType(place, PsiParenthesizedExpression.class); @@ -3073,7 +3073,7 @@ public class HighlightUtil extends HighlightUtilBase { } } else if (PsiUtil.isAccessedForReading((PsiExpression)place)) { - final PsiMethod getterPrototype = PropertyUtil.generateGetterPrototype(psiField); + final PsiMethod getterPrototype = PropertyUtilBase.generateGetterPrototype(psiField); final PsiMethod getter = containingClass.findMethodBySignature(getterPrototype, true); if (getter != null && PsiUtil.isAccessible(getter, place, accessObjectClass)) { QuickFixAction.registerQuickFixAction(error, QUICK_FIX_FACTORY.createReplaceInaccessibleFieldWithGetterSetterFix(place, getter, false)); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PostHighlightingVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PostHighlightingVisitor.java index d9a9a2340f9b..3876037ffa46 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PostHighlightingVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PostHighlightingVisitor.java @@ -50,10 +50,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.impl.PsiClassImplUtil; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.SuperMethodsSearch; -import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.PsiUtilCore; +import com.intellij.psi.util.*; import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.ConcurrentFactoryMap; import com.intellij.codeInspection.unusedImport.UnusedImportInspection; @@ -227,7 +224,7 @@ class PostHighlightingVisitor { } } if (parent instanceof PsiMethod) { - if (myUnusedSymbolInspection.isIgnoreAccessors() && PropertyUtil.isSimplePropertyAccessor((PsiMethod)parent)) { + if (myUnusedSymbolInspection.isIgnoreAccessors() && PropertyUtilBase.isSimplePropertyAccessor((PsiMethod)parent)) { return null; } if (compareVisibilities((PsiModifierListOwner)parent, myUnusedSymbolInspection.getMethodVisibility())) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java index 6ff54eb7b78b..e39753cd7866 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java @@ -568,8 +568,33 @@ public class CFGBuilder { } } + /** + * Inlines given lambda. Lambda parameters are assumed to be assigned already (if necessary). + *

+ * Stack before: ... + *

+ * Stack after: ... lambdaResult + * + * @param lambda lambda to inline + * @param resultNullness a required return value nullness + * @return this builder + */ public CFGBuilder inlineLambda(PsiLambdaExpression lambda, Nullness resultNullness) { - myAnalyzer.inlineLambda(lambda, resultNullness); + PsiElement body = lambda.getBody(); + PsiExpression expression = LambdaUtil.extractSingleExpressionFromBody(body); + if (expression != null) { + pushExpression(expression); + boxUnbox(expression, LambdaUtil.getFunctionalInterfaceReturnType(lambda)); + if(resultNullness == Nullness.NOT_NULL) { + checkNotNull(expression, NullabilityProblem.nullableFunctionReturn); + } + } else if(body instanceof PsiCodeBlock) { + PsiVariable variable = createTempVariable(LambdaUtil.getFunctionalInterfaceReturnType(lambda)); + myAnalyzer.inlineBlock((PsiCodeBlock)body, resultNullness, variable); + push(getFactory().getVarFactory().createVariableValue(variable, false)); + } else { + pushUnknown(); + } return this; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 288a39f330f7..276a0482e5a7 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -63,8 +63,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { private final ExceptionTransfer myRuntimeException; private final ExceptionTransfer myError; private final PsiType myAssertionError; - private PsiLambdaExpression myLambdaExpression = null; - private boolean myForceNotNullLambdaResult = false; + private InlinedBlockContext myInlinedBlockContext; ControlFlowAnalyzer(final DfaValueFactory valueFactory, @NotNull PsiElement codeFragment, boolean ignoreAssertions, boolean inlining) { myInlining = inlining; @@ -685,34 +684,42 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { startElement(statement); PsiExpression returnValue = statement.getReturnValue(); - if (returnValue != null) { - returnValue.accept(this); - PsiMethod method = PsiTreeUtil.getParentOfType(statement, PsiMethod.class, true, PsiMember.class, PsiLambdaExpression.class); - if (method != null) { - generateBoxingUnboxingInstructionFor(returnValue, method.getReturnType()); - } - else { - final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(statement, PsiLambdaExpression.class, true, PsiMember.class); - if (lambdaExpression != null) { - generateBoxingUnboxingInstructionFor(returnValue, LambdaUtil.getFunctionalInterfaceReturnType(lambdaExpression)); - } - } - } - if (myLambdaExpression == null) { + if (myInlinedBlockContext != null) { if (returnValue != null) { + DfaVariableValue var = myFactory.getVarFactory().createVariableValue(myInlinedBlockContext.myTarget, false); + addInstruction(new PushInstruction(var, null, true)); + returnValue.accept(this); + generateBoxingUnboxingInstructionFor(returnValue, var.getVariableType()); + if (myInlinedBlockContext.myForceNonNullBlockResult) { + addInstruction(new CheckNotNullInstruction(returnValue, NullabilityProblem.nullableFunctionReturn)); + } + addInstruction(new AssignInstruction(returnValue, null)); + addInstruction(new PopInstruction()); + } + + controlTransfer(new InstructionTransfer(getEndOffset(myInlinedBlockContext.myCodeBlock), getVariablesInside( + myInlinedBlockContext.myCodeBlock)), myTrapStack); + } else { + + if (returnValue != null) { + returnValue.accept(this); + PsiMethod method = PsiTreeUtil.getParentOfType(statement, PsiMethod.class, true, PsiMember.class, PsiLambdaExpression.class); + if (method != null) { + generateBoxingUnboxingInstructionFor(returnValue, method.getReturnType()); + } + else { + final PsiLambdaExpression lambdaExpression = + PsiTreeUtil.getParentOfType(statement, PsiLambdaExpression.class, true, PsiMember.class); + if (lambdaExpression != null) { + generateBoxingUnboxingInstructionFor(returnValue, LambdaUtil.getFunctionalInterfaceReturnType(lambdaExpression)); + } + } addInstruction(new CheckReturnValueInstruction(returnValue)); } + addInstruction(new ReturnInstruction(myFactory.controlTransfer(ReturnTransfer.INSTANCE, myTrapStack), statement)); } - else { - if (returnValue == null) { - pushUnknown(); - } else if (myForceNotNullLambdaResult) { - addInstruction(new CheckNotNullInstruction(returnValue, NullabilityProblem.nullableFunctionReturn)); - } - controlTransfer(new InstructionTransfer(getEndOffset(myLambdaExpression), getVariablesInside(myLambdaExpression)), myTrapStack); - } finishElement(statement); } @@ -1765,34 +1772,41 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { @Override public void visitClass(PsiClass aClass) { } - void inlineLambda(PsiLambdaExpression lambda, Nullness resultNullness) { - PsiLambdaExpression oldLambda = myLambdaExpression; - boolean oldForceNotNullLambdaResult = myForceNotNullLambdaResult; + /** + * Inline code block (lambda or method body) into this CFG. Incoming parameters are assumed to be handled already (if necessary) + * + * @param block block to inline + * @param resultNullness desired nullness returned by block return statement + * @param target a variable to store the block result (returned via {@code return} statement) + */ + void inlineBlock(@NotNull PsiCodeBlock block, @NotNull Nullness resultNullness, @NotNull PsiVariable target) { + InlinedBlockContext oldBlock = myInlinedBlockContext; // Transfer value is pushed to avoid emptying stack beyond this point addInstruction(new PushInstruction(myFactory.controlTransfer(ReturnTransfer.INSTANCE, this.myTrapStack), null)); - myLambdaExpression = lambda; - myForceNotNullLambdaResult = resultNullness == Nullness.NOT_NULL; - startElement(lambda); + myInlinedBlockContext = new InlinedBlockContext(block, resultNullness == Nullness.NOT_NULL, target); + startElement(block); try { - PsiElement body = lambda.getBody(); - Objects.requireNonNull(body).accept(this); - if (body instanceof PsiCodeBlock) { - // return value for void or incomplete lambda - pushUnknown(); - } - else if (body instanceof PsiExpression) { - generateBoxingUnboxingInstructionFor((PsiExpression)body, LambdaUtil.getFunctionalInterfaceReturnType(lambda)); - if (myForceNotNullLambdaResult) { - addInstruction(new CheckNotNullInstruction((PsiExpression)body, NullabilityProblem.nullableFunctionReturn)); - } - } + block.accept(this); + // return value for void or incomplete block + pushUnknown(); } finally { - finishElement(lambda); - myLambdaExpression = oldLambda; - myForceNotNullLambdaResult = oldForceNotNullLambdaResult; - // Pop transfer value (which is second value in stack now) - addInstruction(new SpliceInstruction(2, 0)); + finishElement(block); + myInlinedBlockContext = oldBlock; + // Pop transfer value + addInstruction(new PopInstruction()); + } + } + + public static class InlinedBlockContext { + final PsiCodeBlock myCodeBlock; + final boolean myForceNonNullBlockResult; + final PsiVariable myTarget; + + public InlinedBlockContext(PsiCodeBlock codeBlock, boolean forceNonNullBlockResult, PsiVariable target) { + myCodeBlock = codeBlock; + myForceNonNullBlockResult = forceNonNullBlockResult; + myTarget = target; } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaFactType.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaFactType.java index c0a686327d6e..5d3b62aae1a0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaFactType.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaFactType.java @@ -133,6 +133,48 @@ public abstract class DfaFactType extends Key { return fact.toString(); } }; + /** + * This fact represents a set of possible types of this value + * {@link TypeConstraint#EMPTY} value is equivalent to absent fact (not constrained) + */ + public static final DfaFactType TYPE_CONSTRAINT = new DfaFactType("Type") { + @Nullable + @Override + TypeConstraint fromDfaValue(DfaValue value) { + if(value instanceof DfaTypeValue) { + TypeConstraint constraint = TypeConstraint.EMPTY.withInstanceofValue((DfaTypeValue)value); + return constraint == null || constraint.isEmpty() ? null : constraint; + } + return null; + } + + @Override + boolean isSuper(@Nullable TypeConstraint superFact, @Nullable TypeConstraint subFact) { + return superFact == null || (subFact != null && superFact.isSuperStateOf(subFact)); + } + + @Nullable + @Override + TypeConstraint intersectFacts(@NotNull TypeConstraint left, @NotNull TypeConstraint right) { + for (DfaPsiType type : right.getInstanceofValues()) { + left = left.withInstanceofValue(type); + if (left == null) return null; + } + for (DfaPsiType type : right.getNotInstanceofValues()) { + left = left.withNotInstanceofValue(type); + if (left == null) return null; + } + return left; + } + + @Nullable + @Override + TypeConstraint unionFacts(@NotNull TypeConstraint left, @NotNull TypeConstraint right) { + if(left.isSuperStateOf(right)) return left; + if(right.isSuperStateOf(left)) return right; + return null; + } + }; private DfaFactType(String name) { super("DfaFactType: " + name); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java index e59cf69e61d6..f8d8ef30ed02 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java @@ -19,7 +19,6 @@ import com.intellij.codeInspection.dataFlow.value.DfaConstValue; import com.intellij.codeInspection.dataFlow.value.DfaRelationValue; import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; -import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -56,13 +55,6 @@ public interface DfaMemoryState { @Nullable T getValueFact(@NotNull DfaFactType factType, @NotNull DfaValue value); - /** - * @param value to determine its type - * @return value type at this state if known (possibly erased) - */ - @Nullable - PsiType getValueType(DfaValue value); - void flushFields(); void flushVariable(DfaVariableValue variable); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index 3ea7c590c4df..ad60aab3cfff 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -1068,23 +1068,6 @@ public class DfaMemoryStateImpl implements DfaMemoryState { return factType.fromDfaValue(value); } - @Nullable - @Override - public PsiType getValueType(DfaValue value) { - if (value instanceof DfaTypeValue) { - return ((DfaTypeValue)value).getDfaType().getPsiType(); - } - if (value instanceof DfaVariableValue) { - DfaVariableState state = getVariableState((DfaVariableValue)value); - Set values = state.getInstanceofValues(); - if (!values.isEmpty()) { - return values.iterator().next().getPsiType(); - } - return ((DfaVariableValue)value).getVariableType(); - } - return null; - } - @NotNull private DfaValue resolveVariableValue(DfaVariableValue var) { DfaConstValue constValue = getConstantValue(var); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java index a73f2330c532..aa565fb491f7 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java @@ -20,117 +20,49 @@ import com.intellij.codeInspection.dataFlow.value.DfaPsiType; import com.intellij.codeInspection.dataFlow.value.DfaTypeValue; import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiPrimitiveType; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.Objects; class DfaVariableState { - @NotNull final Set myInstanceofValues; - @NotNull final Set myNotInstanceofValues; @NotNull final DfaFactMap myFactMap; private final int myHash; DfaVariableState(@NotNull DfaVariableValue dfaVar) { - this(Collections.emptySet(), Collections.emptySet(), dfaVar.getInherentFacts()); + this(dfaVar.getInherentFacts()); } public boolean isSuperStateOf(DfaVariableState that) { - if(!that.myNotInstanceofValues.containsAll(myNotInstanceofValues)) return false; - if(!that.myInstanceofValues.containsAll(myInstanceofValues)) return false; return myFactMap.isSuperStateOf(that.myFactMap); } - DfaVariableState(@NotNull Set instanceofValues, - @NotNull Set notInstanceofValues, - @NotNull DfaFactMap factMap) { - myInstanceofValues = instanceofValues; - myNotInstanceofValues = notInstanceofValues; + DfaVariableState(@NotNull DfaFactMap factMap) { myFactMap = factMap; - myHash = Objects.hash(myInstanceofValues, myNotInstanceofValues, myFactMap); - } - - private boolean checkInstanceofValue(@NotNull DfaPsiType dfaType) { - if (myInstanceofValues.contains(dfaType)) return true; - - for (DfaPsiType dfaTypeValue : myNotInstanceofValues) { - if (dfaTypeValue.isAssignableFrom(dfaType)) return false; - } - - for (DfaPsiType dfaTypeValue : myInstanceofValues) { - if (!dfaType.isConvertibleFrom(dfaTypeValue)) return false; - } - - return true; + myHash = myFactMap.hashCode(); } @Nullable DfaVariableState withInstanceofValue(@NotNull DfaTypeValue dfaType) { if (dfaType.getDfaType().getPsiType() instanceof PsiPrimitiveType) return this; - - if (checkInstanceofValue(dfaType.getDfaType())) { - DfaVariableState result = dfaType.isNullable() ? withFact(DfaFactType.CAN_BE_NULL, true) : this; - List moreGeneric = ContainerUtil.newArrayList(); - for (DfaPsiType alreadyInstanceof : myInstanceofValues) { - if (dfaType.getDfaType().isAssignableFrom(alreadyInstanceof)) { - return result; - } - if (alreadyInstanceof.isAssignableFrom(dfaType.getDfaType())) { - moreGeneric.add(alreadyInstanceof); - } - } - - HashSet newInstanceof = ContainerUtil.newHashSet(myInstanceofValues); - newInstanceof.removeAll(moreGeneric); - newInstanceof.add(dfaType.getDfaType()); - result = createCopy(newInstanceof, myNotInstanceofValues, result.myFactMap); - return result; - } - - return null; + TypeConstraint typeConstraint = getTypeConstraint(); + TypeConstraint newTypeConstraint = typeConstraint.withInstanceofValue(dfaType); + if (newTypeConstraint == null) return null; + DfaVariableState result = dfaType.isNullable() ? withFact(DfaFactType.CAN_BE_NULL, true) : this; + return result.withFact(DfaFactType.TYPE_CONSTRAINT, newTypeConstraint); } @Nullable DfaVariableState withNotInstanceofValue(@NotNull DfaTypeValue dfaType) { - if (myNotInstanceofValues.contains(dfaType.getDfaType())) return this; - - for (DfaPsiType dfaTypeValue : myInstanceofValues) { - if (dfaType.getDfaType().isAssignableFrom(dfaTypeValue)) return null; - } - - List moreSpecific = ContainerUtil.newArrayList(); - for (DfaPsiType alreadyNotInstanceof : myNotInstanceofValues) { - if (alreadyNotInstanceof.isAssignableFrom(dfaType.getDfaType())) { - return this; - } - if (dfaType.getDfaType().isAssignableFrom(alreadyNotInstanceof)) { - moreSpecific.add(alreadyNotInstanceof); - } - } - - HashSet newNotInstanceof = ContainerUtil.newHashSet(myNotInstanceofValues); - newNotInstanceof.removeAll(moreSpecific); - newNotInstanceof.add(dfaType.getDfaType()); - return createCopy(myInstanceofValues, newNotInstanceof, myFactMap); + TypeConstraint typeConstraint = getTypeConstraint(); + TypeConstraint newTypeConstraint = typeConstraint.withNotInstanceofValue(dfaType); + return newTypeConstraint == null ? null : withFact(DfaFactType.TYPE_CONSTRAINT, newTypeConstraint); } @NotNull DfaVariableState withoutType(@NotNull DfaPsiType type) { - if (myInstanceofValues.contains(type)) { - HashSet newInstanceof = ContainerUtil.newHashSet(myInstanceofValues); - newInstanceof.remove(type); - return createCopy(newInstanceof, myNotInstanceofValues, myFactMap); - } - if (myNotInstanceofValues.contains(type)) { - HashSet newNotInstanceof = ContainerUtil.newHashSet(myNotInstanceofValues); - newNotInstanceof.remove(type); - return createCopy(myInstanceofValues, newNotInstanceof, myFactMap); - } - return this; + return withFact(DfaFactType.TYPE_CONSTRAINT, getTypeConstraint().withoutType(type)); } public int hashCode() { @@ -141,35 +73,16 @@ class DfaVariableState { if (obj == this) return true; if (!(obj instanceof DfaVariableState)) return false; DfaVariableState aState = (DfaVariableState) obj; - return myHash == aState.myHash && - myInstanceofValues.equals(aState.myInstanceofValues) && - myNotInstanceofValues.equals(aState.myNotInstanceofValues) && - Objects.equals(myFactMap, aState.myFactMap); + return myHash == aState.myHash && Objects.equals(myFactMap, aState.myFactMap); } @NotNull - protected DfaVariableState createCopy(@NotNull Set instanceofValues, - @NotNull Set notInstanceofValues, - @NotNull DfaFactMap factMap) { - return new DfaVariableState(instanceofValues, notInstanceofValues, factMap); + protected DfaVariableState createCopy(@NotNull DfaFactMap factMap) { + return new DfaVariableState(factMap); } public String toString() { - @NonNls StringBuilder buf = new StringBuilder("State:"); - - if (!myInstanceofValues.isEmpty()) { - buf.append(" instanceof ").append(StringUtil.join(myInstanceofValues, ",")); - } - - if (!myNotInstanceofValues.isEmpty()) { - buf.append(" not instanceof ").append(StringUtil.join(myNotInstanceofValues, ",")); - } - - String factString = myFactMap.toString(); - if(!factString.isEmpty()) { - buf.append(" ").append(factString); - } - return buf.toString(); + return "State: " + myFactMap; } @NotNull @@ -189,7 +102,7 @@ class DfaVariableState { @NotNull DfaVariableState withFact(DfaFactType type, T value) { DfaFactMap factMap = myFactMap.with(type, value); - return myFactMap.equals(factMap) ? this : createCopy(myInstanceofValues, myNotInstanceofValues, factMap); + return myFactMap.equals(factMap) ? this : createCopy(factMap); } DfaVariableState withoutFact(DfaFactType type) { @@ -199,9 +112,7 @@ class DfaVariableState { @Nullable DfaVariableState intersectFact(DfaFactType type, T value) { DfaFactMap factMap = myFactMap.intersect(type, value); - return factMap == null - ? null - : myFactMap.equals(factMap) ? this : createCopy(myInstanceofValues, myNotInstanceofValues, factMap); + return factMap == null ? null : myFactMap.equals(factMap) ? this : createCopy(factMap); } @NotNull @@ -215,13 +126,9 @@ class DfaVariableState { } @NotNull - public Set getInstanceofValues() { - return myInstanceofValues; - } - - @NotNull - public Set getNotInstanceofValues() { - return myNotInstanceofValues; + public TypeConstraint getTypeConstraint() { + TypeConstraint fact = getFact(DfaFactType.TYPE_CONSTRAINT); + return fact == null ? TypeConstraint.EMPTY : fact; } @Nullable diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullParameterConstraintChecker.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullParameterConstraintChecker.java index 5c11c64277d5..7cb6b67b7753 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullParameterConstraintChecker.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullParameterConstraintChecker.java @@ -33,7 +33,6 @@ import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import java.util.Collection; -import java.util.Collections; import java.util.Set; /** @@ -138,8 +137,7 @@ class NullParameterConstraintChecker extends DataFlowRunner { super(factory); for (PsiParameter parameter : myPossiblyViolatedParameters) { setVariableState(getFactory().getVarFactory().createVariableValue(parameter, false), - new DfaVariableState(Collections.emptySet(), Collections.emptySet(), - DfaFactMap.EMPTY.with(DfaFactType.CAN_BE_NULL, true))); + new DfaVariableState(DfaFactMap.EMPTY.with(DfaFactType.CAN_BE_NULL, true))); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 957a3dc01807..f925ad9a9c88 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -23,6 +23,7 @@ import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; +import com.intellij.psi.impl.search.JavaOverridingMethodsSearcher; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; @@ -477,6 +478,26 @@ public class StandardInstructionVisitor extends InstructionVisitor { } } + @NotNull + private static PsiMethod findSpecificMethod(@NotNull PsiMethod method, @NotNull DfaMemoryState state, @Nullable DfaValue qualifier) { + if (qualifier == null || !PsiUtil.canBeOverridden(method)) { + return method; + } + TypeConstraint constraint = state.getValueFact(DfaFactType.TYPE_CONSTRAINT, qualifier); + PsiClass specificQualifierClass = PsiUtil.resolveClassInClassTypeOnly(constraint == null ? null : constraint.getPsiType()); + PsiClass qualifierClass = method.getContainingClass(); + if (specificQualifierClass != null && qualifierClass != null && + !specificQualifierClass.equals(qualifierClass) && + InheritanceUtil.isInheritorOrSelf(specificQualifierClass, qualifierClass, true)) { + PsiMethod realMethod = + JavaOverridingMethodsSearcher.findOverridingMethod(method.getProject(), specificQualifierClass, method, qualifierClass); + if (realMethod != null) { + return realMethod; + } + } + return method; + } + @NotNull private static DfaValue getMethodResultValue(MethodCallInstruction instruction, @Nullable DfaValue qualifierValue, @@ -520,19 +541,13 @@ public class StandardInstructionVisitor extends InstructionVisitor { Nullness nullability = instruction.getReturnNullability(); PsiMethod targetMethod = instruction.getTargetMethod(); if (targetMethod != null) { - PsiClass specificQualifierClass = PsiUtil.resolveClassInClassTypeOnly(state.getValueType(qualifierValue)); - PsiClass qualifierClass = targetMethod.getContainingClass(); - if (specificQualifierClass != null && qualifierClass != null && - !specificQualifierClass.equals(qualifierClass) && - InheritanceUtil.isInheritorOrSelf(specificQualifierClass, qualifierClass, true)) { - PsiMethod realMethod = specificQualifierClass.findMethodBySignature(targetMethod, true); - if (realMethod != null && realMethod != targetMethod) { - nullability = DfaPsiUtil.getElementNullability(type, realMethod); - PsiType returnType = realMethod.getReturnType(); - if(returnType != null && TypeConversionUtil.erasure(type).isAssignableFrom(returnType)) { - // possibly covariant return type - type = returnType; - } + PsiMethod realMethod = findSpecificMethod(targetMethod, state, qualifierValue); + if (realMethod != targetMethod) { + nullability = DfaPsiUtil.getElementNullability(type, realMethod); + PsiType returnType = realMethod.getReturnType(); + if (returnType != null && TypeConversionUtil.erasure(type).isAssignableFrom(returnType)) { + // possibly covariant return type + type = returnType; } } if (nullability == Nullness.UNKNOWN) { @@ -700,7 +715,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { return checkComparisonWithKnownValue(instruction, runner, memState, relationType, leftValue, rightValue); } } - + if (dfaRight instanceof DfaConstValue && dfaLeft instanceof DfaVariableValue) { Object value = ((DfaConstValue)dfaRight).getValue(); if (value instanceof Number) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java index b0f7d6172c4e..99ab239dccb3 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java @@ -430,10 +430,11 @@ class StateMerger { for (Map.Entry entry : states.entrySet()) { DfaVariableValue var = entry.getKey(); DfaVariableState variableState = entry.getValue(); - for (DfaPsiType type : variableState.getInstanceofValues()) { + TypeConstraint typeConstraint = variableState.getTypeConstraint(); + for (DfaPsiType type : typeConstraint.getInstanceofValues()) { result.add(new InstanceofFact(var, true, type)); } - for (DfaPsiType type : variableState.getNotInstanceofValues()) { + for (DfaPsiType type : typeConstraint.getNotInstanceofValues()) { result.add(new InstanceofFact(var, false, type)); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/TypeConstraint.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/TypeConstraint.java new file mode 100644 index 000000000000..363785b1c3ee --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/TypeConstraint.java @@ -0,0 +1,201 @@ +/* + * Copyright 2000-2017 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.codeInspection.dataFlow; + +import com.intellij.codeInspection.dataFlow.value.DfaPsiType; +import com.intellij.codeInspection.dataFlow.value.DfaTypeValue; +import com.intellij.psi.PsiPrimitiveType; +import com.intellij.psi.PsiType; +import com.intellij.util.containers.ContainerUtil; +import one.util.streamex.EntryStream; +import one.util.streamex.StreamEx; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * Immutable class representing a number of non-primitive type constraints applied to some value. + * There are two types of constrains: value is instance of some type and value is not an instance of some type. + */ +public final class TypeConstraint { + /** + * An instance representing no constraints + */ + public static final TypeConstraint EMPTY = new TypeConstraint(Collections.emptySet(), Collections.emptySet()); + + @NotNull private final Set myInstanceofValues; + @NotNull private final Set myNotInstanceofValues; + + private TypeConstraint(@NotNull Set instanceofValues, @NotNull Set notInstanceofValues) { + myInstanceofValues = instanceofValues; + myNotInstanceofValues = notInstanceofValues; + } + + private static TypeConstraint create(@NotNull Set instanceofValues, @NotNull Set notInstanceofValues) { + if (instanceofValues.isEmpty() && notInstanceofValues.isEmpty()) { + return EMPTY; + } + if (instanceofValues.isEmpty()) { + instanceofValues = Collections.emptySet(); + } + else if (instanceofValues.size() == 1) { + instanceofValues = Collections.singleton(instanceofValues.iterator().next()); + } + if (notInstanceofValues.isEmpty()) { + notInstanceofValues = Collections.emptySet(); + } + else if (notInstanceofValues.size() == 1) { + notInstanceofValues = Collections.singleton(notInstanceofValues.iterator().next()); + } + return new TypeConstraint(instanceofValues, notInstanceofValues); + } + + boolean checkInstanceofValue(@NotNull DfaPsiType dfaType) { + if (myInstanceofValues.contains(dfaType)) return true; + + for (DfaPsiType dfaTypeValue : myNotInstanceofValues) { + if (dfaTypeValue.isAssignableFrom(dfaType)) return false; + } + + for (DfaPsiType dfaTypeValue : myInstanceofValues) { + if (!dfaType.isConvertibleFrom(dfaTypeValue)) return false; + } + + return true; + } + + @Nullable + TypeConstraint withInstanceofValue(@NotNull DfaTypeValue dfaType) { + return withInstanceofValue(dfaType.getDfaType()); + } + + @Nullable + TypeConstraint withInstanceofValue(@NotNull DfaPsiType type) { + if (type.getPsiType() instanceof PsiPrimitiveType) return this; + + if (!checkInstanceofValue(type)) { + return null; + } + List moreGeneric = new ArrayList<>(); + for (DfaPsiType alreadyInstanceof : myInstanceofValues) { + if (type.isAssignableFrom(alreadyInstanceof)) { + return this; + } + if (alreadyInstanceof.isAssignableFrom(type)) { + moreGeneric.add(alreadyInstanceof); + } + } + + Set newInstanceof = ContainerUtil.newHashSet(myInstanceofValues); + newInstanceof.removeAll(moreGeneric); + newInstanceof.add(type); + return create(newInstanceof, myNotInstanceofValues); + } + + @Nullable + TypeConstraint withNotInstanceofValue(@NotNull DfaTypeValue dfaType) { + return withNotInstanceofValue(dfaType.getDfaType()); + } + + @Nullable + TypeConstraint withNotInstanceofValue(DfaPsiType type) { + if (myNotInstanceofValues.contains(type)) return this; + + for (DfaPsiType dfaTypeValue : myInstanceofValues) { + if (type.isAssignableFrom(dfaTypeValue)) return null; + } + + List moreSpecific = new ArrayList<>(); + for (DfaPsiType alreadyNotInstanceof : myNotInstanceofValues) { + if (alreadyNotInstanceof.isAssignableFrom(type)) { + return this; + } + if (type.isAssignableFrom(alreadyNotInstanceof)) { + moreSpecific.add(alreadyNotInstanceof); + } + } + + Set newNotInstanceof = ContainerUtil.newHashSet(myNotInstanceofValues); + newNotInstanceof.removeAll(moreSpecific); + newNotInstanceof.add(type); + return create(myInstanceofValues, newNotInstanceof); + } + + @NotNull + TypeConstraint withoutType(@NotNull DfaPsiType type) { + if (myInstanceofValues.contains(type)) { + HashSet newInstanceof = ContainerUtil.newHashSet(myInstanceofValues); + newInstanceof.remove(type); + return create(newInstanceof, myNotInstanceofValues); + } + if (myNotInstanceofValues.contains(type)) { + HashSet newNotInstanceof = ContainerUtil.newHashSet(myNotInstanceofValues); + newNotInstanceof.remove(type); + return create(myInstanceofValues, newNotInstanceof); + } + return this; + } + + @Nullable + public PsiType getPsiType() { + if (myInstanceofValues.isEmpty()) { + return null; + } + return myInstanceofValues.iterator().next().getPsiType(); + } + + boolean isSuperStateOf(@NotNull TypeConstraint that) { + return that.myNotInstanceofValues.containsAll(myNotInstanceofValues) && that.myInstanceofValues.containsAll(myInstanceofValues); + } + + @NotNull + public Set getInstanceofValues() { + return Collections.unmodifiableSet(myInstanceofValues); + } + + @NotNull + public Set getNotInstanceofValues() { + return Collections.unmodifiableSet(myNotInstanceofValues); + } + + public boolean isEmpty() { + return myInstanceofValues.isEmpty() && myNotInstanceofValues.isEmpty(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TypeConstraint that = (TypeConstraint)o; + return Objects.equals(myInstanceofValues, that.myInstanceofValues) && + Objects.equals(myNotInstanceofValues, that.myNotInstanceofValues); + } + + @Override + public int hashCode() { + return Objects.hash(myInstanceofValues, myNotInstanceofValues); + } + + @Override + public String toString() { + return EntryStream.of("instanceof ", myInstanceofValues, + "not instanceof ", myNotInstanceofValues) + .removeValues(Set::isEmpty) + .mapKeyValue((prefix, set) -> StreamEx.of(set).joining(",", prefix, "")) + .joining(" "); + } +} diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ValuableDataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ValuableDataFlowRunner.java index d0fe9b2518fc..a06ce2a04483 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ValuableDataFlowRunner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ValuableDataFlowRunner.java @@ -16,7 +16,6 @@ package com.intellij.codeInspection.dataFlow; -import com.intellij.codeInspection.dataFlow.value.DfaPsiType; import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; @@ -25,8 +24,6 @@ import com.intellij.util.containers.FList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Set; - /** * @author Gregory.Shrago */ @@ -74,34 +71,30 @@ class ValuableDataFlowRunner extends DataFlowRunner { myConcatenation = FList.emptyList(); } - private ValuableDfaVariableState(Set instanceofValues, - Set notInstanceofValues, - DfaValue value, + private ValuableDfaVariableState(DfaValue value, @NotNull FList concatenation, @NotNull DfaFactMap factMap) { - super(instanceofValues, notInstanceofValues, factMap); + super(factMap); myValue = value; myConcatenation = concatenation; } @NotNull @Override - protected DfaVariableState createCopy(@NotNull Set instanceofValues, - @NotNull Set notInstanceofValues, - @NotNull DfaFactMap factMap) { - return new ValuableDfaVariableState(instanceofValues, notInstanceofValues, myValue, myConcatenation, factMap); + protected DfaVariableState createCopy(@NotNull DfaFactMap factMap) { + return new ValuableDfaVariableState(myValue, myConcatenation, factMap); } @NotNull @Override public DfaVariableState withValue(@Nullable final DfaValue value) { if (value == myValue) return this; - return new ValuableDfaVariableState(myInstanceofValues, myNotInstanceofValues, value, myConcatenation, myFactMap); + return new ValuableDfaVariableState(value, myConcatenation, myFactMap); } ValuableDfaVariableState withExpression(@NotNull final FList concatenation) { if (concatenation == myConcatenation) return this; - return new ValuableDfaVariableState(myInstanceofValues, myNotInstanceofValues, myValue, concatenation, myFactMap); + return new ValuableDfaVariableState(myValue, concatenation, myFactMap); } @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspectionBase.java index 5430b6dcc8f1..b4c1c6aad903 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspectionBase.java @@ -24,7 +24,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.psi.*; import com.intellij.psi.javadoc.*; -import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; @@ -297,7 +297,7 @@ public class JavaDocLocalInspectionBase extends BaseJavaBatchLocalInspectionTool if (IGNORE_DEPRECATED && isDeprecated(psiMethod)) { return null; } - if (myIgnoreSimpleAccessors && PropertyUtil.isSimplePropertyAccessor(psiMethod)) { + if (myIgnoreSimpleAccessors && PropertyUtilBase.isSimplePropertyAccessor(psiMethod)) { return null; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java index 7a1daea8dd16..b05cbaa64ce7 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java @@ -384,7 +384,7 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo NullableNotNullManager manager, final String anno, final List annoToRemove, @NotNull ProblemsHolder holder) { String propName = JavaCodeStyleManager.getInstance(project).variableNameToPropertyName(field.getName(), VariableKind.FIELD); final boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); - final PsiMethod getter = PropertyUtil.findPropertyGetter(field.getContainingClass(), propName, isStatic, false); + final PsiMethod getter = PropertyUtilBase.findPropertyGetter(field.getContainingClass(), propName, isStatic, false); final PsiIdentifier nameIdentifier = getter == null ? null : getter.getNameIdentifier(); if (nameIdentifier != null && nameIdentifier.isPhysical()) { if (PropertyUtil.isSimpleGetter(getter)) { @@ -406,7 +406,7 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo } final PsiClass containingClass = field.getContainingClass(); - final PsiMethod setter = PropertyUtil.findPropertySetter(containingClass, propName, isStatic, false); + final PsiMethod setter = PropertyUtilBase.findPropertySetter(containingClass, propName, isStatic, false); if (setter != null && setter.isPhysical() && PropertyUtil.isSimpleSetter(setter)) { final PsiParameter[] parameters = setter.getParameterList().getParameters(); assert parameters.length == 1 : setter.getText(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/redundantCast/RedundantCastInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/redundantCast/RedundantCastInspection.java index 7f3f83ad01b3..493364907e1d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/redundantCast/RedundantCastInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/redundantCast/RedundantCastInspection.java @@ -15,7 +15,6 @@ */ package com.intellij.codeInspection.redundantCast; -import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInspection.*; import com.intellij.codeInspection.miscGenerics.GenericsInspectionToolBase; @@ -45,7 +44,6 @@ public class RedundantCastInspection extends GenericsInspectionToolBase { private static final String DISPLAY_NAME = InspectionsBundle.message("inspection.redundant.cast.display.name"); @NonNls private static final String SHORT_NAME = "RedundantCast"; - public boolean IGNORE_ANNOTATED_METHODS; public boolean IGNORE_SUSPICIOUS_METHOD_CALLS; @@ -71,7 +69,7 @@ public class RedundantCastInspection extends GenericsInspectionToolBase { @Override public void writeSettings(@NotNull Element node) throws WriteExternalException { - if (IGNORE_ANNOTATED_METHODS || IGNORE_SUSPICIOUS_METHOD_CALLS) { + if (IGNORE_SUSPICIOUS_METHOD_CALLS) { super.writeSettings(node); } } @@ -80,7 +78,6 @@ public class RedundantCastInspection extends GenericsInspectionToolBase { public JComponent createOptionsPanel() { final MultipleCheckboxOptionsPanel optionsPanel = new MultipleCheckboxOptionsPanel(this); optionsPanel.addCheckbox("Ignore casts in suspicious collections method calls", "IGNORE_SUSPICIOUS_METHOD_CALLS"); - optionsPanel.addCheckbox("Ignore casts to invoke @NotNull method which overrides @Nullable", "IGNORE_ANNOTATED_METHODS"); return optionsPanel; } @@ -90,25 +87,7 @@ public class RedundantCastInspection extends GenericsInspectionToolBase { PsiTypeElement castType = cast.getCastType(); if (operand == null || castType == null) return null; PsiElement parent = PsiUtil.skipParenthesizedExprUp(cast.getParent()); - if (parent instanceof PsiReferenceExpression) { - if (IGNORE_ANNOTATED_METHODS) { - final PsiElement gParent = parent.getParent(); - if (gParent instanceof PsiMethodCallExpression) { - final PsiMethod psiMethod = ((PsiMethodCallExpression)gParent).resolveMethod(); - if (psiMethod != null && NullableNotNullManager.isNotNull(psiMethod)) { - final PsiClass superClass = PsiUtil.resolveClassInType(operand.getType()); - final PsiClass containingClass = psiMethod.getContainingClass(); - if (containingClass != null && superClass != null && containingClass.isInheritor(superClass, true)) { - for (PsiMethod method : psiMethod.findSuperMethods(superClass)) { - if (NullableNotNullManager.isNullable(method)) { - return null; - } - } - } - } - } - } - } else if (parent instanceof PsiExpressionList) { + if (parent instanceof PsiExpressionList) { final PsiElement gParent = parent.getParent(); if (gParent instanceof PsiMethodCallExpression && IGNORE_SUSPICIOUS_METHOD_CALLS) { final String message = SuspiciousMethodCallUtil diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrowsDeclarationInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrowsDeclarationInspection.java index e2669f837062..f9216e6a3f14 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrowsDeclarationInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrowsDeclarationInspection.java @@ -81,6 +81,7 @@ public class RedundantThrowsDeclarationInspection extends GlobalJavaBatchInspect if (unThrown == null) return null; PsiMethod psiMethod = (PsiMethod)refMethod.getElement(); + if (psiMethod == null) return null; PsiClassType[] throwsList = psiMethod.getThrowsList().getReferencedTypes(); PsiJavaCodeReferenceElement[] throwsRefs = psiMethod.getThrowsList().getReferenceElements(); List problems = null; diff --git a/java/java-analysis-impl/src/org/jetbrains/java/generate/inspection/FieldNotUsedInToStringInspection.java b/java/java-analysis-impl/src/org/jetbrains/java/generate/inspection/FieldNotUsedInToStringInspection.java index 7ad9b1e7f3cb..9117705794f9 100644 --- a/java/java-analysis-impl/src/org/jetbrains/java/generate/inspection/FieldNotUsedInToStringInspection.java +++ b/java/java-analysis-impl/src/org/jetbrains/java/generate/inspection/FieldNotUsedInToStringInspection.java @@ -19,6 +19,7 @@ import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.psi.*; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -145,7 +146,7 @@ public class FieldNotUsedInToStringInspection extends AbstractToStringInspection } else { myUnusedMethods.remove(method); - final PsiField field = PropertyUtil.findPropertyFieldByMember(method); + final PsiField field = PropertyUtilBase.findPropertyFieldByMember(method); myUnusedFields.remove(field); } } diff --git a/java/java-analysis-impl/src/org/jetbrains/java/generate/psi/PsiAdapter.java b/java/java-analysis-impl/src/org/jetbrains/java/generate/psi/PsiAdapter.java index 3c923deb54f5..6069c93e4458 100644 --- a/java/java-analysis-impl/src/org/jetbrains/java/generate/psi/PsiAdapter.java +++ b/java/java-analysis-impl/src/org/jetbrains/java/generate/psi/PsiAdapter.java @@ -25,7 +25,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; @@ -492,7 +492,7 @@ public class PsiAdapter { if (!isGetterMethod(method)) { return null; } - return PropertyUtil.getPropertyNameByGetter(method); + return PropertyUtilBase.getPropertyNameByGetter(method); } /** diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java index 366c2d997c17..dd5c8322cb1e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java @@ -410,8 +410,8 @@ public class ExpectedTypesProvider { private void visitMethodReturnType(final PsiMethod scopeMethod, PsiType type, boolean tailTypeSemicolon) { if (type != null) { NullableComputable expectedName; - if (PropertyUtil.isSimplePropertyAccessor(scopeMethod)) { - expectedName = () -> PropertyUtil.getPropertyName(scopeMethod); + if (PropertyUtilBase.isSimplePropertyAccessor(scopeMethod)) { + expectedName = () -> PropertyUtilBase.getPropertyName(scopeMethod); } else { expectedName = ExpectedTypeInfoImpl.NULL; diff --git a/java/java-impl/src/com/intellij/codeInsight/JavaTargetElementEvaluator.java b/java/java-impl/src/com/intellij/codeInsight/JavaTargetElementEvaluator.java index 076c8b39aa6c..20be3f05a031 100644 --- a/java/java-impl/src/com/intellij/codeInsight/JavaTargetElementEvaluator.java +++ b/java/java-impl/src/com/intellij/codeInsight/JavaTargetElementEvaluator.java @@ -15,10 +15,14 @@ */ package com.intellij.codeInsight; +import com.intellij.codeInspection.dataFlow.CommonDataflow; +import com.intellij.codeInspection.dataFlow.DfaFactType; +import com.intellij.codeInspection.dataFlow.TypeConstraint; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.Computable; import com.intellij.psi.*; +import com.intellij.psi.impl.search.JavaOverridingMethodsSearcher; import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; @@ -38,18 +42,19 @@ public class JavaTargetElementEvaluator extends TargetElementEvaluatorEx2 implem public static final int NEW_AS_CONSTRUCTOR = 0x04; public static final int THIS_ACCEPTED = 0x10; public static final int SUPER_ACCEPTED = 0x20; + public static final int USE_DFA = 0x40; @Override public int getAllAdditionalFlags() { - return NEW_AS_CONSTRUCTOR | THIS_ACCEPTED | SUPER_ACCEPTED; + return NEW_AS_CONSTRUCTOR | THIS_ACCEPTED | SUPER_ACCEPTED | USE_DFA; } /** - * Accepts THIS or SUPER but not NEW_AS_CONSTRUCTOR. + * Accepts THIS or SUPER or USE_DFA but not NEW_AS_CONSTRUCTOR. */ @Override public int getAdditionalDefinitionSearchFlags() { - return THIS_ACCEPTED | SUPER_ACCEPTED; + return THIS_ACCEPTED | SUPER_ACCEPTED | USE_DFA; } /** @@ -78,9 +83,31 @@ public class JavaTargetElementEvaluator extends TargetElementEvaluatorEx2 implem return ((PsiClassType)type).resolve(); } } + if (targetElement instanceof PsiMethod && BitUtil.isSet(flags, USE_DFA)) { + PsiElement realMethod = findOverridingMethod(editor, offset, (PsiMethod)targetElement); + if (realMethod != null) return realMethod; + } return super.adjustTargetElement(editor, offset, flags, targetElement); } + @Nullable + private static PsiElement findOverridingMethod(Editor editor, int offset, PsiMethod method) { + PsiClass qualifierClass = method.getContainingClass(); + if (qualifierClass == null || !PsiUtil.canBeOverridden(method)) return null; + PsiReference reference = TargetElementUtil.findReference(editor, offset); + if (!(reference instanceof PsiReferenceExpression) || !reference.isReferenceTo(method)) return null; + PsiExpression qualifier = ((PsiReferenceExpression)reference).getQualifierExpression(); + if (qualifier == null) return null; + TypeConstraint constraint = CommonDataflow.getExpressionFact(qualifier, DfaFactType.TYPE_CONSTRAINT); + if (constraint == null) return null; + PsiClass specificQualifierClass = PsiUtil.resolveClassInClassTypeOnly(constraint.getPsiType()); + if (specificQualifierClass == null || specificQualifierClass.equals(qualifierClass) || + !InheritanceUtil.isInheritorOrSelf(specificQualifierClass, qualifierClass, true)) { + return null; + } + return JavaOverridingMethodsSearcher.findOverridingMethod(method.getProject(), specificQualifierClass, method, qualifierClass); + } + @Override public boolean isAcceptableNamedParent(@NotNull PsiElement parent) { return !(parent instanceof PsiDocTag); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/FunctionalExpressionCompletionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/FunctionalExpressionCompletionProvider.java index 08e308081606..21c05936c6c8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/FunctionalExpressionCompletionProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/FunctionalExpressionCompletionProvider.java @@ -23,6 +23,7 @@ import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.icons.AllIcons; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; @@ -53,6 +54,7 @@ public class FunctionalExpressionCompletionProvider extends CompletionProvider FUNCTIONAL_EXPR_ITEM = Key.create("FUNCTIONAL_EXPR_ITEM"); private static boolean isLambdaContext(@NotNull PsiElement element) { final PsiElement rulezzRef = element.getParent(); @@ -105,13 +107,16 @@ public class FunctionalExpressionCompletionProvider extends CompletionProvider {}") .withTypeText(functionalInterfaceType.getPresentableText()) .withIcon(AllIcons.Nodes.Function); - LookupElement lambdaElement = builder.withAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE); - result.consume(smart ? lambdaElement : PrioritizedLookupElement.withPriority(lambdaElement, 1)); + builder.putUserData(FUNCTIONAL_EXPR_ITEM, true); + result.consume(builder.withAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE)); } addMethodReferenceVariants( smart, addInheritors, parameters, matcher, functionalInterfaceType, functionalInterfaceMethod, params, originalPosition, substitutor, - element -> result.consume(smart ? JavaSmartCompletionContributor.decorate(element, Arrays.asList(expectedTypes)) : element)); + element -> { + element.putUserData(FUNCTIONAL_EXPR_ITEM, true); + result.consume(smart ? JavaSmartCompletionContributor.decorate(element, Arrays.asList(expectedTypes)) : element); + }); } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 74f10b38b543..97f00f85661b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -252,7 +252,7 @@ public class JavaCompletionContributor extends CompletionContributor { PrefixMatcher matcher = result.getPrefixMatcher(); PsiElement parent = position.getParent(); - if (JavaKeywordCompletion.addWildcardExtendsSuper(result, position)) { + if (new JavaKeywordCompletion(parameters, session).addWildcardExtendsSuper(result, position)) { return; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java index 3eb7b1cb2b29..fe58d856404f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java @@ -166,6 +166,7 @@ public class JavaKeywordCompletion { private final JavaCompletionSession mySession; private final PsiElement myPosition; private final String myPrefix; + private final PrefixMatcher myKeywordMatcher; private final List myResults = new ArrayList<>(); private final PsiElement myPrevLeaf; @@ -173,6 +174,7 @@ public class JavaKeywordCompletion { myParameters = parameters; mySession = session; myPrefix = session.getMatcher().getPrefix(); + myKeywordMatcher = new FixingLayoutPlainMatcher(myPrefix); myPosition = parameters.getPosition(); myPrevLeaf = prevSignificantLeaf(myPosition); @@ -185,7 +187,7 @@ public class JavaKeywordCompletion { } private void addKeyword(LookupElement element) { - if (element.getLookupString().startsWith(myPrefix)) { + if (myKeywordMatcher.isStartMatch(element.getLookupString())) { myResults.add(element); } } @@ -313,10 +315,10 @@ public class JavaKeywordCompletion { addExtendsImplements(); } - static boolean addWildcardExtendsSuper(CompletionResultSet result, PsiElement position) { + boolean addWildcardExtendsSuper(CompletionResultSet result, PsiElement position) { if (JavaMemberNameCompletionContributor.INSIDE_TYPE_PARAMS_PATTERN.accepts(position)) { for (String keyword : ContainerUtil.ar(PsiKeyword.EXTENDS, PsiKeyword.SUPER)) { - if (keyword.startsWith(result.getPrefixMatcher().getPrefix())) { + if (myKeywordMatcher.isStartMatch(keyword)) { LookupElement item = BasicExpressionCompletionContributor.createKeywordLookupItem(position, keyword); result.addElement(new OverridableSpace(item, TailType.HUMBLE_SPACE_BEFORE_WORD)); } @@ -394,7 +396,7 @@ public class JavaKeywordCompletion { } } - if ((isInsideParameterList(myPosition) || isAtResourceVariableStart(myPosition) || isAtCatchVariableStart(myPosition)) && + if ((isInsideParameterList(myPosition) || isAtCatchOrResourceVariableStart(myPosition)) && !psiElement().afterLeaf(PsiKeyword.FINAL).accepts(myPosition) && !AFTER_DOT.accepts(myPosition)) { addKeyword(TailTypeDecorator.withTail(createKeyword(PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD)); @@ -730,12 +732,14 @@ public class JavaKeywordCompletion { info -> InheritanceUtil.isInheritor(info.getType(), CommonClassNames.JAVA_LANG_CLASS)) != null; } - private static boolean isAtResourceVariableStart(PsiElement position) { - return psiElement().insideStarting(psiElement(PsiTypeElement.class).withParent(PsiResourceList.class)).accepts(position); - } - - private static boolean isAtCatchVariableStart(PsiElement position) { - return psiElement().insideStarting(psiElement(PsiTypeElement.class).withParent(PsiCatchSection.class)).accepts(position); + private static boolean isAtCatchOrResourceVariableStart(PsiElement position) { + PsiElement type = PsiTreeUtil.getParentOfType(position, PsiTypeElement.class); + if (type != null && type.getTextRange().getStartOffset() == position.getTextRange().getStartOffset()) { + PsiElement parent = type.getParent(); + if (parent instanceof PsiVariable) parent = parent.getParent(); + return parent instanceof PsiCatchSection || parent instanceof PsiResourceList; + } + return false; } private void addBreakContinue() { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java index 2819dddfb0a8..f79f0770b2f3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -30,10 +30,7 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; -import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.PsiUtilCore; +import com.intellij.psi.util.*; import com.intellij.refactoring.introduceField.InplaceIntroduceFieldPopup; import com.intellij.refactoring.introduceVariable.IntroduceVariableBase; import com.intellij.util.ArrayUtil; @@ -112,7 +109,7 @@ public class JavaMemberNameCompletionContributor extends CompletionContributor { if (variableKind == VariableKind.PARAMETER) { final PsiMethod method = PsiTreeUtil.getParentOfType(var, PsiMethod.class); if (method != null) { - propertyName = PropertyUtil.getPropertyName(method); + propertyName = PropertyUtilBase.getPropertyName(method); } if (method != null && method.getName().startsWith("with")) { propertyName = StringUtil.decapitalize(method.getName().substring(4)); @@ -393,7 +390,7 @@ public class JavaMemberNameCompletionContributor extends CompletionContributor { if (staticContext && (modifierList != null && !modifierList.hasModifierProperty(PsiModifier.STATIC))) continue; if (fieldType.equals(varType)) { - final String getterName = PropertyUtil.suggestGetterName(field); + final String getterName = PropertyUtilBase.suggestGetterName(field); if ((psiClass.findMethodsByName(getterName, true).length == 0 || psiClass.findMethodBySignature(GenerateMembersUtil.generateGetterPrototype(field), true) == null)) { propertyHandlers.add(getterName); @@ -401,7 +398,7 @@ public class JavaMemberNameCompletionContributor extends CompletionContributor { } if (PsiType.VOID.equals(varType)) { - final String setterName = PropertyUtil.suggestSetterName(field); + final String setterName = PropertyUtilBase.suggestSetterName(field); if ((psiClass.findMethodsByName(setterName, true).length == 0 || psiClass.findMethodBySignature(GenerateMembersUtil.generateSetterPrototype(field), true) == null)) { propertyHandlers.add(setterName); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java index dd34eb662dbc..7b6dbda1d7f9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.ExceptionUtil; import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementWeigher; +import com.intellij.codeInsight.lookup.TypedLookupItem; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Conditions; import com.intellij.openapi.util.Key; @@ -28,10 +29,7 @@ import com.intellij.patterns.ElementPattern; import com.intellij.psi.*; import com.intellij.psi.filters.getters.MembersGetter; import com.intellij.psi.impl.source.tree.JavaElementType; -import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.*; import com.intellij.psi.util.proximity.KnownElementWeigher; import com.intellij.util.ThreeState; import com.intellij.util.containers.ContainerUtil; @@ -133,6 +131,8 @@ public class PreferByKindWeigher extends LookupElementWeigher { annoMethod, probableKeyword, castVariable, + expectedTypeVariable, + funExpr, variable, getter, qualifiedWithField, @@ -171,13 +171,17 @@ public class PreferByKindWeigher extends LookupElementWeigher { if (object instanceof PsiLocalVariable || object instanceof PsiParameter || object instanceof PsiThisExpression || object instanceof PsiField && !((PsiField)object).hasModifierProperty(PsiModifier.STATIC)) { - return MyResult.variable; + return isExpectedTypeItem(item) ? MyResult.expectedTypeVariable : MyResult.variable; } if (object instanceof String && item.getUserData(JavaCompletionUtil.SUPER_METHOD_PARAMETERS) == Boolean.TRUE) { return MyResult.superMethodParameters; } + if (item.getUserData(FunctionalExpressionCompletionProvider.FUNCTIONAL_EXPR_ITEM) != null) { + return MyResult.funExpr; + } + if (object instanceof PsiMethod) { PsiClass containingClass = ((PsiMethod)object).getContainingClass(); if (containingClass != null && CommonClassNames.JAVA_UTIL_COLLECTIONS.equals(containingClass.getQualifiedName())) { @@ -248,6 +252,12 @@ public class PreferByKindWeigher extends LookupElementWeigher { return MyResult.normal; } + private boolean isExpectedTypeItem(@NotNull LookupElement item) { + TypedLookupItem typed = item.as(TypedLookupItem.CLASS_CONDITION_KEY); + PsiType itemType = typed == null ? null : typed.getType(); + return itemType != null && Arrays.stream(myExpectedTypes).anyMatch(info -> info.getType().isAssignableFrom(itemType)); + } + @NotNull private ThreeState isProbableKeyword(String keyword) { if (PsiKeyword.RETURN.equals(keyword)) { @@ -315,7 +325,7 @@ public class PreferByKindWeigher extends LookupElementWeigher { if (!(object instanceof PsiMethod)) return false; PsiMethod method = (PsiMethod)object; - if (!PropertyUtil.hasGetterName(method)) return false; + if (!PropertyUtilBase.hasGetterName(method)) return false; return !KnownElementWeigher.isGetClass(method); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java index 0409c50d7233..2835852739e4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -31,6 +31,7 @@ import com.intellij.psi.filters.element.ExcludeSillyAssignment; import com.intellij.psi.impl.search.MethodDeepestSuperSearcher; import com.intellij.psi.scope.ElementClassFilter; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.CommonProcessors; import org.jetbrains.annotations.NotNull; @@ -170,15 +171,15 @@ class RecursionWeigher extends LookupElementWeigher { @Nullable private String getSetterPropertyName(@Nullable PsiMethod calledMethod) { - if (PropertyUtil.isSimplePropertySetter(calledMethod)) { + if (PropertyUtilBase.isSimplePropertySetter(calledMethod)) { assert calledMethod != null; - return PropertyUtil.getPropertyName(calledMethod); + return PropertyUtilBase.getPropertyName(calledMethod); } PsiReferenceExpression reference = ExcludeSillyAssignment.getAssignedReference(myPosition); if (reference != null) { PsiElement target = reference.resolve(); if (target instanceof PsiField) { - return PropertyUtil.suggestPropertyName((PsiField)target); + return PropertyUtilBase.suggestPropertyName((PsiField)target); } } return null; @@ -189,12 +190,12 @@ class RecursionWeigher extends LookupElementWeigher { if (prop == null) return false; if (lookupObject instanceof PsiField && - prop.equals(PropertyUtil.suggestPropertyName((PsiField)lookupObject))) { + prop.equals(PropertyUtilBase.suggestPropertyName((PsiField)lookupObject))) { return true; } if (lookupObject instanceof PsiMethod && - PropertyUtil.isSimplePropertyGetter((PsiMethod)lookupObject) && - prop.equals(PropertyUtil.getPropertyName((PsiMethod)lookupObject))) { + PropertyUtilBase.isSimplePropertyGetter((PsiMethod)lookupObject) && + prop.equals(PropertyUtilBase.getPropertyName((PsiMethod)lookupObject))) { return true; } return false; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java index 9b7b878a6146..7f3048553d0b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java @@ -125,7 +125,7 @@ class SmartCastProvider extends CompletionProvider { if (info.getKind() == ExpectedTypeInfo.TYPE_OR_SUPERTYPE) { InheritanceUtil.processSupers(infoClass, true, superClass -> { if (!CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) { - result.consume(JavaPsiFacade.getElementFactory(superClass.getProject()).createType(superClass)); + result.consume(JavaPsiFacade.getElementFactory(superClass.getProject()).createType(CompletionUtil.getOriginalOrSelf(superClass))); } return true; }); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterOrSetterFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterOrSetterFix.java index 88f8a1724d4d..73194b1ad888 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterOrSetterFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterOrSetterFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -25,6 +25,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -47,7 +48,7 @@ public class CreateGetterOrSetterFix implements IntentionAction, LowPriorityActi myCreateGetter = createGetter; myCreateSetter = createSetter; myField = field; - myPropertyName = PropertyUtil.suggestPropertyName(field); + myPropertyName = PropertyUtilBase.suggestPropertyName(field); } @Override @@ -86,13 +87,13 @@ public class CreateGetterOrSetterFix implements IntentionAction, LowPriorityActi } if (myCreateGetter){ - if (isStaticFinal(myField) || PropertyUtil.findPropertyGetter(aClass, myPropertyName, isStatic(myField), false) != null){ + if (isStaticFinal(myField) || PropertyUtilBase.findPropertyGetter(aClass, myPropertyName, isStatic(myField), false) != null){ return false; } } if (myCreateSetter){ - if(isFinal(myField) || PropertyUtil.findPropertySetter(aClass, myPropertyName, isStatic(myField), false) != null){ + if(isFinal(myField) || PropertyUtilBase.findPropertySetter(aClass, myPropertyName, isStatic(myField), false) != null){ return false; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterSetterPropertyFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterSetterPropertyFromUsageFix.java index dea4567383b6..6825a380770a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterSetterPropertyFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterSetterPropertyFromUsageFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -21,6 +21,7 @@ import com.intellij.psi.PsiField; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiMethodCallExpression; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -41,10 +42,10 @@ public class CreateGetterSetterPropertyFromUsageFix extends CreatePropertyFromUs @Override protected boolean checkTargetClasses(List classes, String methodName) { - String propertyName = PropertyUtil.getPropertyName(methodName); + String propertyName = PropertyUtilBase.getPropertyName(methodName); if (propertyName == null) return false; - String getterName = PropertyUtil.suggestGetterName(propertyName, null); - String setterName = PropertyUtil.suggestSetterName(propertyName); + String getterName = PropertyUtilBase.suggestGetterName(propertyName, null); + String setterName = PropertyUtilBase.suggestSetterName(propertyName); for (PsiClass aClass : classes) { if (aClass.findMethodsByName(getterName, false).length > 0 || aClass.findMethodsByName(setterName, false).length > 0) return false; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreatePropertyFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreatePropertyFromUsageFix.java index 35afe19cde74..69f51adac58e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreatePropertyFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreatePropertyFromUsageFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -35,6 +35,7 @@ import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.util.RefactoringUtil; @@ -84,7 +85,7 @@ public class CreatePropertyFromUsageFix extends CreateFromUsageBaseFix implement PsiReferenceExpression ref = myMethodCall.getMethodExpression(); String methodName = myMethodCall.getMethodExpression().getReferenceName(); LOG.assertTrue(methodName != null); - String propertyName = PropertyUtil.getPropertyName(methodName); + String propertyName = PropertyUtilBase.getPropertyName(methodName); if (propertyName == null || propertyName.isEmpty()) return false; String getterOrSetter = null; @@ -321,7 +322,7 @@ public class CreatePropertyFromUsageFix extends CreateFromUsageBaseFix implement private static String getVariableName(PsiMethodCallExpression methodCall, boolean isStatic) { JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(methodCall.getProject()); String methodName = methodCall.getMethodExpression().getReferenceName(); - String propertyName = PropertyUtil.getPropertyName(methodName); + String propertyName = PropertyUtilBase.getPropertyName(methodName); if (propertyName != null && !propertyName.isEmpty()) { VariableKind kind = isStatic ? VariableKind.STATIC_FIELD : VariableKind.FIELD; return codeStyleManager.propertyNameToVariableName(propertyName, kind); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFieldOrPropertyFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFieldOrPropertyFix.java index 58c451778094..0aa00b8975bb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFieldOrPropertyFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFieldOrPropertyFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PropertyMemberType; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -126,7 +127,7 @@ public class CreateFieldOrPropertyFix implements IntentionAction, LocalQuickFix boolean first = true; @NonNls final String TYPE_NAME_VAR = "TYPE_NAME_VAR"; for (GenerationInfo prototype : prototypes) { - final PsiTypeElement typeElement = PropertyUtil.getPropertyTypeElement(prototype.getPsiMember()); + final PsiTypeElement typeElement = PropertyUtilBase.getPropertyTypeElement(prototype.getPsiMember()); if (first) { first = false; builder.replaceElement(typeElement, TYPE_NAME_VAR, expression, true); diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/IfConditionFixer.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/IfConditionFixer.java index 108a68f6bb52..62f6c3e16a5e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/IfConditionFixer.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/IfConditionFixer.java @@ -18,6 +18,7 @@ package com.intellij.codeInsight.editorActions.smartEnter; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; /** @@ -53,5 +54,13 @@ public class IfConditionFixer implements Fixer { doc.insertString(condition.getTextRange().getEndOffset(), ")"); } } + else if (psiElement instanceof PsiExpression && psiElement.getParent() instanceof PsiExpressionStatement) { + PsiElement prevLeaf = PsiTreeUtil.prevVisibleLeaf(psiElement); + if (prevLeaf != null && prevLeaf.textMatches(PsiKeyword.IF)) { + Document doc = editor.getDocument(); + doc.insertString(psiElement.getTextRange().getEndOffset(), ")"); + doc.insertString(psiElement.getTextRange().getStartOffset(), "("); + } + } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java index c83cd6b59b67..10ea5acc23d8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -33,6 +33,7 @@ import com.intellij.psi.scope.processor.VariablesProcessor; import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.util.*; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NonNls; @@ -234,7 +235,7 @@ public class GenerateDelegateHandler implements LanguageCodeInsightActionHandler if (targetClass instanceof PsiTypeParameter) { LinkedHashSet meths = new LinkedHashSet<>(); for (PsiClass superClass : targetClass.getSupers()) { - meths.addAll(Arrays.asList(superClass.getAllMethods())); + ContainerUtil.addAll(meths, superClass.getAllMethods()); } allMethods = meths.toArray(new PsiMethod[meths.size()]); } @@ -377,7 +378,7 @@ public class GenerateDelegateHandler implements LanguageCodeInsightActionHandler final PsiClass containingClass = method.getContainingClass(); if (containingClass == null || CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName())) continue; final PsiType returnType = method.getReturnType(); - if (returnType != null && PropertyUtil.isSimplePropertyGetter(method) && helper.isAccessible(method, aClass, aClass) && + if (returnType != null && PropertyUtilBase.isSimplePropertyGetter(method) && helper.isAccessible(method, aClass, aClass) && returnType instanceof PsiClassType && !(PsiTreeUtil.isAncestor(method, element, false) && targetClass != aClass)) { result.add(new PsiMethodMember(method, TypeConversionUtil.getSuperClassSubstitutor( containingClass, aClass,PsiSubstitutor.EMPTY))); } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateFieldOrPropertyHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateFieldOrPropertyHandler.java index 79a39f38408e..d957084080e4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateFieldOrPropertyHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateFieldOrPropertyHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -22,6 +22,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PropertyMemberType; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -71,8 +72,8 @@ public class GenerateFieldOrPropertyHandler extends GenerateMembersHandlerBase { for (GenerationInfo info : infos) { PsiMember member = info.getPsiMember(); if (!(member instanceof PsiMethod)) continue; - if (myMemberType == PropertyMemberType.GETTER && PropertyUtil.isSimplePropertyGetter((PsiMethod)member) || - myMemberType == PropertyMemberType.SETTER && PropertyUtil.isSimplePropertySetter((PsiMethod)member)) { + if (myMemberType == PropertyMemberType.GETTER && PropertyUtilBase.isSimplePropertyGetter((PsiMethod)member) || + myMemberType == PropertyMemberType.SETTER && PropertyUtilBase.isSimplePropertySetter((PsiMethod)member)) { targetMember = member; break; } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java index 538d28a62bab..e4d227e3c07d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java @@ -609,15 +609,15 @@ public class GenerateMembersUtil { //java bean getters/setters public static PsiMethod generateSimpleGetterPrototype(@NotNull PsiField field) { - return generatePrototype(field, PropertyUtil.generateGetterPrototype(field)); + return generatePrototype(field, PropertyUtilBase.generateGetterPrototype(field)); } public static PsiMethod generateSimpleSetterPrototype(@NotNull PsiField field) { - return generatePrototype(field, PropertyUtil.generateSetterPrototype(field)); + return generatePrototype(field, PropertyUtilBase.generateSetterPrototype(field)); } public static PsiMethod generateSimpleSetterPrototype(PsiField field, PsiClass targetClass) { - return generatePrototype(field, PropertyUtil.generateSetterPrototype(field, targetClass)); + return generatePrototype(field, PropertyUtilBase.generateSetterPrototype(field, targetClass)); } //custom getters/setters @@ -680,7 +680,7 @@ public class GenerateMembersUtil { catch (IncorrectOperationException e) { if (ignoreInvalidTemplate) { LOG.info(e); - result = isGetter ? PropertyUtil.generateGetterPrototype(field) : PropertyUtil.generateSetterPrototype(field); + result = isGetter ? PropertyUtilBase.generateGetterPrototype(field) : PropertyUtilBase.generateSetterPrototype(field); assert result != null : field.getText(); } else { diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GetterSetterPrototypeProvider.java b/java/java-impl/src/com/intellij/codeInsight/generation/GetterSetterPrototypeProvider.java index 12a7e7cf9cef..af315591b188 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GetterSetterPrototypeProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GetterSetterPrototypeProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -22,6 +22,7 @@ import com.intellij.psi.PsiField; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; public abstract class GetterSetterPrototypeProvider { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.getterSetterProvider"); @@ -74,7 +75,7 @@ public abstract class GetterSetterPrototypeProvider { if (getterSetter != null) return getterSetter; } } - final PsiMethod propertyGetterSetter = PropertyUtil.findPropertyGetter(aClass, propertyName, isStatic, false); + final PsiMethod propertyGetterSetter = PropertyUtilBase.findPropertyGetter(aClass, propertyName, isStatic, false); if (propertyGetterSetter != null) { return new PsiMethod[] {propertyGetterSetter}; } diff --git a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java index a5f6a3a0ef07..62135ecb3d38 100644 --- a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java @@ -236,7 +236,10 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc return; } - int index = ParameterInfoUtils.getCurrentParameterIndex(o.getNode(), context.getOffset(), JavaTokenType.COMMA); + int offset = context.getOffset(); + TextRange elRange = o.getTextRange(); + int index = offset <= elRange.getStartOffset() || offset >= elRange.getEndOffset() + ? -1 : ParameterInfoUtils.getCurrentParameterIndex(o.getNode(), offset, JavaTokenType.COMMA); context.setCurrentParameter(index); Object[] candidates = context.getObjectsToView(); diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/UnrollLoopAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/UnrollLoopAction.java index 65dce6e74b89..97ac1938c530 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/UnrollLoopAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/UnrollLoopAction.java @@ -33,8 +33,15 @@ import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.Objects; +import static com.siyeh.ig.callMatcher.CallMatcher.anyOf; +import static com.siyeh.ig.callMatcher.CallMatcher.staticCall; + public class UnrollLoopAction extends PsiElementBaseIntentionAction { - private static final CallMatcher LIST_CONSTRUCTOR = CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_ARRAYS, "asList"); + private static final CallMatcher LIST_CONSTRUCTOR = anyOf(staticCall(CommonClassNames.JAVA_UTIL_ARRAYS, "asList"), + staticCall(CommonClassNames.JAVA_UTIL_LIST, "of")); + private static final CallMatcher SINGLETON_CONSTRUCTOR = + anyOf(staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "singleton", "singletonList").parameterCount(1), + staticCall(CommonClassNames.JAVA_UTIL_LIST, "of").parameterTypes("E")); @Override public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull final PsiElement element) { @@ -42,14 +49,17 @@ public class UnrollLoopAction extends PsiElementBaseIntentionAction { if (loop == null) return false; if (!(loop.getParent() instanceof PsiCodeBlock)) return false; PsiExpression iteratedValue = ExpressionUtils.resolveExpression(loop.getIteratedValue()); + PsiParameter iterationParameter = loop.getIterationParameter(); if (extractExpressions(iteratedValue).length == 0) return false; PsiStatement[] statements = ControlFlowUtils.unwrapBlock(loop.getBody()); if (statements.length == 0) return false; if (Arrays.stream(statements).anyMatch(PsiDeclarationStatement.class::isInstance)) return false; - if (isBreakChain(loop)) { - statements = Arrays.copyOfRange(statements, 0, statements.length - 1); - } + if (VariableAccessUtils.variableIsAssigned(iterationParameter, loop)) return false; + //if (isBreakChain(loop)) { + // statements = Arrays.copyOfRange(statements, 0, statements.length - 1); + //} for (PsiStatement statement : statements) { + if (isLoopBreak(statement)) continue; boolean acceptable = PsiTreeUtil.processElements(statement, e -> { if (e instanceof PsiBreakStatement && ((PsiBreakStatement)e).findExitedStatement() == loop) return false; if (e instanceof PsiContinueStatement && ((PsiContinueStatement)e).findContinuedStatement() == loop) return false; @@ -72,9 +82,15 @@ public class UnrollLoopAction extends PsiElementBaseIntentionAction { } if (expression instanceof PsiMethodCallExpression) { PsiMethodCallExpression call = (PsiMethodCallExpression)expression; - if (LIST_CONSTRUCTOR.test(call) && MethodCallUtils.isVarArgCall(call)) { + if (SINGLETON_CONSTRUCTOR.test(call)) { return call.getArgumentList().getExpressions(); } + if (LIST_CONSTRUCTOR.test(call)) { + PsiExpression[] args = call.getArgumentList().getExpressions(); + if (args.length > 1 || MethodCallUtils.isVarArgCall(call)) { + return args; + } + } } return PsiExpression.EMPTY_ARRAY; } @@ -96,7 +112,6 @@ public class UnrollLoopAction extends PsiElementBaseIntentionAction { PsiForeachStatement loop = PsiTreeUtil.getParentOfType(element, PsiForeachStatement.class); if (loop == null) return; if (!(loop.getParent() instanceof PsiCodeBlock)) return; - boolean breakChain = isBreakChain(loop); PsiExpression iteratedValue = loop.getIteratedValue(); PsiExpression[] expressions = extractExpressions(ExpressionUtils.resolveExpression(iteratedValue)); if (expressions.length == 0) return; @@ -115,22 +130,23 @@ public class UnrollLoopAction extends PsiElementBaseIntentionAction { } PsiStatement body = copy.getBody(); assert body != null; + PsiElement[] children; if (body instanceof PsiBlockStatement) { - PsiElement[] children = ((PsiBlockStatement)body).getCodeBlock().getChildren(); - PsiElement parent = anchor.getParent(); - PsiElement currentAnchor = anchor; + children = ((PsiBlockStatement)body).getCodeBlock().getChildren(); // Skip {braces} - Arrays.stream(children, 1, children.length - 1).forEach(child -> parent.addBefore(child, currentAnchor)); + children = Arrays.copyOfRange(children, 1, children.length-1); + } else { + children = new PsiElement[]{body}; } - if (breakChain) { - PsiStatement lastStatement = PsiTreeUtil.getPrevSiblingOfType(anchor, PsiStatement.class); - if (lastStatement instanceof PsiIfStatement) { - PsiIfStatement ifStatement = (PsiIfStatement)lastStatement; + for(PsiElement child : children) { + PsiElement added = anchor.getParent().addBefore(child, anchor); + if (added instanceof PsiIfStatement && isLoopBreak((PsiStatement)added)) { + PsiIfStatement ifStatement = (PsiIfStatement)added; PsiExpression condition = Objects.requireNonNull(ifStatement.getCondition()); PsiStatement thenBranch = Objects.requireNonNull(ifStatement.getThenBranch()); String negated = BoolUtils.getNegatedExpressionText(condition); condition.replace(factory.createExpressionFromText(negated, condition)); - PsiBlockStatement block = (PsiBlockStatement)thenBranch.replace(factory.createStatementFromText("{}", lastStatement)); + PsiBlockStatement block = (PsiBlockStatement)thenBranch.replace(factory.createStatementFromText("{}", added)); anchor = block.getCodeBlock().getLastChild(); } } @@ -140,19 +156,11 @@ public class UnrollLoopAction extends PsiElementBaseIntentionAction { ct.deleteAndRestoreComments(loop); } - /** - * @param loop loop to test - * @return true if the last statement is "if(...) break" - */ - private static boolean isBreakChain(PsiForeachStatement loop) { - PsiStatement lastStatement = loop.getBody(); - if (lastStatement instanceof PsiBlockStatement) { - lastStatement = ControlFlowUtils.getLastStatementInBlock(((PsiBlockStatement)lastStatement).getCodeBlock()); - } - if (!(lastStatement instanceof PsiIfStatement)) return false; - PsiIfStatement ifStatement = (PsiIfStatement)lastStatement; - return ifStatement.getElseBranch() == null && - ifStatement.getCondition() != null && - ControlFlowUtils.statementBreaksLoop(ControlFlowUtils.stripBraces(ifStatement.getThenBranch()), loop); + private static boolean isLoopBreak(PsiStatement statement) { + if (!(statement instanceof PsiIfStatement)) return false; + PsiIfStatement ifStatement = (PsiIfStatement)statement; + if (ifStatement.getElseBranch() != null || ifStatement.getCondition() == null) return false; + PsiStatement thenBranch = ControlFlowUtils.stripBraces(ifStatement.getThenBranch()); + return thenBranch instanceof PsiBreakStatement && ((PsiBreakStatement)thenBranch).getLabelIdentifier() == null; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/OptionalPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/OptionalPostfixTemplate.java index 79c6e3558866..072bee170b61 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/OptionalPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/OptionalPostfixTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -16,6 +16,8 @@ package com.intellij.codeInsight.template.postfix.templates; import com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils; +import com.intellij.codeInspection.dataFlow.Nullness; +import com.intellij.codeInspection.dataFlow.NullnessUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiPrimitiveType; @@ -35,23 +37,21 @@ public class OptionalPostfixTemplate extends StringBasedPostfixTemplate { @Override public String getTemplateString(@NotNull PsiElement element) { String className = "Optional"; - String methodName = "ofNullable"; - - if (element instanceof PsiExpression) { - PsiType type = ((PsiExpression)element).getType(); - if (type instanceof PsiPrimitiveType) { - if (PsiType.INT.equals(type)) { - className = "OptionalInt"; - } - else if (PsiType.DOUBLE.equals(type)) { - className = "OptionalDouble"; - } - else if (PsiType.LONG.equals(type)) { - className = "OptionalLong"; - } - methodName = "of"; + + PsiType type = ((PsiExpression)element).getType(); + if (type instanceof PsiPrimitiveType) { + if (PsiType.INT.equals(type)) { + className = "OptionalInt"; + } + else if (PsiType.DOUBLE.equals(type)) { + className = "OptionalDouble"; + } + else if (PsiType.LONG.equals(type)) { + className = "OptionalLong"; } } + + String methodName = Nullness.NOT_NULL.equals(NullnessUtil.getExpressionNullness((PsiExpression)element)) ? "of" : "ofNullable"; return "java.util." + className + "." + methodName + "($expr$)"; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/StreamPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/StreamPostfixTemplate.java index 13f49004a571..86fd754881e4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/StreamPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/StreamPostfixTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -16,15 +16,28 @@ package com.intellij.codeInsight.template.postfix.templates; import com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils; -import com.intellij.psi.PsiElement; +import com.intellij.openapi.util.Condition; +import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.selectorAllExpressionsWithCurrentOffset; public class StreamPostfixTemplate extends StringBasedPostfixTemplate { + private static final Condition IS_SUPPORTED_ARRAY = element -> { + if (!(element instanceof PsiExpression)) return false; + + PsiType type = ((PsiExpression)element).getType(); + if (!(type instanceof PsiArrayType)) return false; + + PsiType componentType = ((PsiArrayType)type).getComponentType(); + if (!(componentType instanceof PsiPrimitiveType)) return true; + + return componentType.equals(PsiType.INT) || componentType.equals(PsiType.LONG) || componentType.equals(PsiType.DOUBLE); + }; + public StreamPostfixTemplate() { - super("stream", "Arrays.stream(expr)", JavaPostfixTemplatesUtils.atLeastJava8Selector(selectorAllExpressionsWithCurrentOffset(JavaPostfixTemplatesUtils.IS_ARRAY))); + super("stream", "Arrays.stream(expr)", JavaPostfixTemplatesUtils.atLeastJava8Selector(selectorAllExpressionsWithCurrentOffset(IS_SUPPORTED_ARRAY))); } @Nullable diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java index 3707f5b5fa82..dd8500f95c7c 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java @@ -42,6 +42,7 @@ import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel; import com.intellij.psi.*; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.safeDelete.SafeDeleteHandler; import com.intellij.ui.HyperlinkAdapter; @@ -520,7 +521,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta //todo store in the graph tool.isIgnoreAccessors()) { final PsiModifierListOwner listOwner = ((RefMethod)element).getElement(); - if (listOwner instanceof PsiMethod && PropertyUtil.isSimplePropertyAccessor((PsiMethod)listOwner)) { + if (listOwner instanceof PsiMethod && PropertyUtilBase.isSimplePropertyAccessor((PsiMethod)listOwner)) { return null; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java index 0a666ff45051..26d4bffd9a0e 100644 --- a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -465,7 +465,7 @@ public class MagicConstantInspection extends BaseJavaLocalInspectionTool { if (!(initializer instanceof PsiLiteralExpression)) return null; Object val = ((PsiLiteralExpression)initializer).getValue(); if (!(val instanceof String)) return null; - PsiMethod setter = PropertyUtil.findPropertySetter(method.getContainingClass(), (String)val, false, false); + PsiMethod setter = PropertyUtilBase.findPropertySetter(method.getContainingClass(), (String)val, false, false); if (setter == null) return null; // try the @beaninfo of the corresponding setter PsiElement navigationElement = setter.getNavigationElement(); @@ -482,12 +482,12 @@ public class MagicConstantInspection extends BaseJavaLocalInspectionTool { PsiClass aClass = method.getContainingClass(); if (aClass == null) return null; - if (PropertyUtil.isSimplePropertyGetter(method)) { - List setters = PropertyUtil.getSetters(aClass, PropertyUtil.getPropertyNameByGetter(method)); + if (PropertyUtilBase.isSimplePropertyGetter(method)) { + List setters = PropertyUtilBase.getSetters(aClass, PropertyUtilBase.getPropertyNameByGetter(method)); if (setters.size() != 1) return null; method = setters.get(0); } - if (!PropertyUtil.isSimplePropertySetter(method)) return null; + if (!PropertyUtilBase.isSimplePropertySetter(method)) return null; PsiDocComment doc = method.getDocComment(); if (doc == null) return null; PsiDocTag beaninfo = doc.findTagByName("beaninfo"); diff --git a/java/java-impl/src/com/intellij/codeInspection/streamMigration/SimplifyForEachInspection.java b/java/java-impl/src/com/intellij/codeInspection/streamMigration/SimplifyForEachInspection.java index 883681e1460f..3ef8f47217b6 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/SimplifyForEachInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/SimplifyForEachInspection.java @@ -110,7 +110,7 @@ public class SimplifyForEachInspection extends BaseJavaBatchLocalInspectionTool } @Nullable - static PsiLambdaExpression extractLambdaFromForEach(PsiMethodCallExpression call) { + static PsiLambdaExpression extractLambdaFromForEach(@NotNull PsiMethodCallExpression call) { PsiExpression qualifier = call.getMethodExpression().getQualifierExpression(); if (qualifier == null || !(STREAM_FOREACH.test(call) || isCollectionForEach(call, qualifier))) return null; PsiExpression arg = call.getArgumentList().getExpressions()[0]; @@ -195,7 +195,8 @@ public class SimplifyForEachInspection extends BaseJavaBatchLocalInspectionTool return result; } - static SimplifyForEachContext from(PsiMethodCallExpression call) { + static SimplifyForEachContext from(@Nullable PsiMethodCallExpression call) { + if (call == null) return null; PsiLambdaExpression lambda = extractLambdaFromForEach(call); if (lambda == null) return null; PsiElement lambdaBody = lambda.getBody(); diff --git a/java/java-impl/src/com/intellij/codeInspection/streamToLoop/SourceOperation.java b/java/java-impl/src/com/intellij/codeInspection/streamToLoop/SourceOperation.java index 477c0bffc4a9..bfa9c3b839ce 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamToLoop/SourceOperation.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamToLoop/SourceOperation.java @@ -28,6 +28,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; +import java.util.Objects; import java.util.function.Consumer; import static com.intellij.codeInspection.streamToLoop.FunctionHelper.replaceVarReference; @@ -106,6 +107,14 @@ abstract class SourceOperation extends Operation { CommonClassNames.JAVA_UTIL_ARRAYS.equals(className)) { return new ForEachSource(args[0]); } + if (name.equals("stream") && + args.length == 3 && + CommonClassNames.JAVA_UTIL_ARRAYS.equals(className) && + args[0].getType() != null && + PsiType.INT.equals(args[1].getType()) && + PsiType.INT.equals(args[2].getType())) { + return new ArraySliceSource(args[0], args[1], args[2]); + } if (supportUnknownSources) { PsiType type = StreamApiUtil.getStreamElementType(call.getType(), false); if (type != null) { @@ -320,6 +329,54 @@ abstract class SourceOperation extends Operation { } } + static class ArraySliceSource extends SourceOperation { + private @NotNull PsiExpression myArray; + private @NotNull PsiExpression myOrigin; + private @NotNull PsiExpression myBound; + private @NotNull PsiType myArrayType; + + ArraySliceSource(@NotNull PsiExpression array, @NotNull PsiExpression origin, @NotNull PsiExpression bound) { + myOrigin = origin; + myBound = bound; + myArray = array; + myArrayType = Objects.requireNonNull(myArray.getType()); + } + + @Override + void rename(String oldName, String newName, StreamToLoopReplacementContext context) { + myOrigin = replaceVarReference(myOrigin, oldName, newName, context); + myBound = replaceVarReference(myBound, oldName, newName, context); + myArray = replaceVarReference(myArray, oldName, newName, context); + } + + @Override + public void registerReusedElements(Consumer consumer) { + consumer.accept(myOrigin); + consumer.accept(myBound); + consumer.accept(myArray); + } + + @Override + String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context) { + String bound = myBound.getText(); + String array = myArray.getText(); + if (!ExpressionUtils.isSimpleExpression(context.createExpression(array))) { + array = context.declare("array", myArrayType.getCanonicalText(), array); + } + if (!ExpressionUtils.isSimpleExpression(context.createExpression(bound))) { + bound = context.declare("bound", "int", bound); + } + String loopVar = context.registerVarName(Arrays.asList("i", "j", "idx")); + String element = outVar.getDeclaration(array + "[" + loopVar + "]"); + return context.getLoopLabel() + + "for(" + "int " + loopVar + " = " + myOrigin.getText() + ";" + + loopVar + "<" + bound + ";" + + loopVar + "++) {\n" + + element + + code + "}\n"; + } + } + private static class StreamIteratorSource extends SourceOperation { private final String myElementType; private PsiMethodCallExpression myCall; diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java index 0cdfd0ac57e3..fe32c0f5f132 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java @@ -25,6 +25,7 @@ import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiReference; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -54,7 +55,7 @@ public class UnusedReturnValue extends GlobalJavaBatchInspectionTool{ if (!refMethod.isReturnValueUsed()) { final PsiMethod psiMethod = (PsiMethod)refMethod.getElement(); if (psiMethod == null) return null; - if (IGNORE_BUILDER_PATTERN && PropertyUtil.isSimplePropertySetter(psiMethod)) return null; + if (IGNORE_BUILDER_PATTERN && PropertyUtilBase.isSimplePropertySetter(psiMethod)) return null; final boolean isNative = psiMethod.hasModifierProperty(PsiModifier.NATIVE); if (refMethod.isExternalOverride() && !isNative) return null; diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValueLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValueLocalInspection.java index 0191c56131d0..7ec7cffee589 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValueLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValueLocalInspection.java @@ -24,6 +24,7 @@ import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.siyeh.ig.psiutils.MethodUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -61,7 +62,7 @@ public class UnusedReturnValueLocalInspection extends BaseJavaLocalInspectionToo public ProblemDescriptor[] checkMethod(@NotNull PsiMethod method, @NotNull InspectionManager manager, boolean isOnTheFly) { if (method.isConstructor() || PsiType.VOID.equals(method.getReturnType()) || - myGlobal.IGNORE_BUILDER_PATTERN && PropertyUtil.isSimplePropertySetter(method) || + myGlobal.IGNORE_BUILDER_PATTERN && PropertyUtilBase.isSimplePropertySetter(method) || method.hasModifierProperty(PsiModifier.NATIVE) || MethodUtils.hasSuper(method) || RefUtil.isImplicitRead(method)) return null; 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 8b56b0a431c6..cf8bf3f4ee5a 100644 --- a/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java +++ b/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java @@ -34,10 +34,7 @@ import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.search.searches.MethodReferencesSearch; import com.intellij.psi.search.searches.OverridingMethodsSearch; -import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiSuperMethodUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.PsiUtilCore; +import com.intellij.psi.util.*; import com.intellij.refactoring.util.JavaNonCodeSearchElementDescriptionProvider; import com.intellij.refactoring.util.NonCodeSearchDescriptionLocation; import com.intellij.usageView.UsageInfo; @@ -177,13 +174,13 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{ final String propertyName = JavaCodeStyleManager.getInstance(getProject()).variableNameToPropertyName(fieldName, VariableKind.FIELD); Set accessors = new THashSet<>(); boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); - PsiMethod getter = PropertyUtil.findPropertyGetterWithType(propertyName, isStatic, field.getType(), - ContainerUtil.iterate(containingClass.getMethods())); + PsiMethod getter = PropertyUtilBase.findPropertyGetterWithType(propertyName, isStatic, field.getType(), + ContainerUtil.iterate(containingClass.getMethods())); if (getter != null) accessors.add(getter); - PsiMethod setter = PropertyUtil.findPropertySetterWithType(propertyName, isStatic, field.getType(), - ContainerUtil.iterate(containingClass.getMethods())); + PsiMethod setter = PropertyUtilBase.findPropertySetterWithType(propertyName, isStatic, field.getType(), + ContainerUtil.iterate(containingClass.getMethods())); if (setter != null) accessors.add(setter); - accessors.addAll(PropertyUtil.getAccessors(containingClass, fieldName)); + accessors.addAll(PropertyUtilBase.getAccessors(containingClass, fieldName)); if (!accessors.isEmpty()) { boolean containsPhysical = ContainerUtil.find(accessors, psiMethod -> psiMethod.isPhysical()) != null; final boolean doSearch = !containsPhysical || askShouldSearchAccessors(fieldName); diff --git a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java index 13330c14052e..5a2afe6db2da 100644 --- a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java +++ b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java @@ -16,28 +16,20 @@ package com.intellij.openapi.projectRoots.impl; import com.intellij.icons.AllIcons; -import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.FileTypes; -import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; -import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.projectRoots.*; import com.intellij.openapi.roots.*; -import com.intellij.openapi.roots.ex.ProjectRootManagerEx; -import com.intellij.openapi.util.EmptyRunnable; -import com.intellij.openapi.util.Key; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.jrt.JrtFileSystem; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.PathUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; @@ -410,7 +402,7 @@ public class JavaSdkImpl extends JavaSdk { addClasses(jdkHomeFile, sdkModificator, isJre); addSources(jdkHomeFile, sdkModificator); - return new MockSdk(jdkName, homePath, jdkName, roots, isJre); + return new MockSdk(jdkName, homePath, jdkName, roots, this); } private static void addClasses(@NotNull File file, @NotNull SdkModificator sdkModificator, boolean isJre) { @@ -544,182 +536,4 @@ public class JavaSdkImpl extends JavaSdk { type == JavadocOrderRootType.getInstance() || type == AnnotationOrderRootType.getInstance(); } - - private class MockSdk implements Sdk, SdkModificator { - private String myJdkName; - private String myHomePath; - @NotNull private String myVersionString; - private final MultiMap myRoots; - private final boolean myIsJre; - - MockSdk(@NotNull String jdkName, - @NotNull String homePath, - @NotNull String versionString, - @NotNull MultiMap roots, - boolean isJre) { - myJdkName = jdkName; - myHomePath = homePath; - myVersionString = versionString; - myRoots = roots; - myIsJre = isJre; - } - - @NotNull - @Override - public SdkTypeId getSdkType() { - return JavaSdkImpl.this; - } - - @NotNull - @Override - public String getName() { - return myJdkName; - } - - @NotNull - @Override - public String getVersionString() { - return myVersionString; - } - - @Override - public String getHomePath() { - return myHomePath; - } - - @Nullable - @Override - public VirtualFile getHomeDirectory() { - return LocalFileSystem.getInstance().findFileByPath(myHomePath); - } - - @Nullable - @Override - public SdkAdditionalData getSdkAdditionalData() { - return null; - } - - @NotNull - @Override - public Sdk clone() { - return new MockSdk(myJdkName, myHomePath, myVersionString, new MultiMap<>(myRoots), myIsJre){ - @NotNull - @Override - public SdkModificator getSdkModificator() { - return this; - } - }; - } - - @NotNull - @Override - public SdkModificator getSdkModificator() { - throwReadOnly(); - return null; - } - - @NotNull - public VirtualFile[] getRoots(@NotNull OrderRootType rootType) { - return myRoots.get(rootType).toArray(VirtualFile.EMPTY_ARRAY); - } - - @Override - public void setName(String name) { - myJdkName = name; - } - - @Override - public void setHomePath(String path) { - myHomePath = path; - } - - @Override - public void setVersionString(@NotNull String versionString) { - myVersionString = versionString; - } - - @Override - public void setSdkAdditionalData(SdkAdditionalData data) { - throwReadOnly(); - } - - @Override - public void addRoot(@NotNull VirtualFile root, @NotNull OrderRootType rootType) { - myRoots.putValue(rootType, root); - } - - @Override - public void removeRoot(@NotNull VirtualFile root, @NotNull OrderRootType rootType) { - myRoots.remove(rootType, root); - } - - @Override - public void removeRoots(@NotNull OrderRootType rootType) { - myRoots.remove(rootType); - } - - @Override - public void removeAllRoots() { - myRoots.clear(); - } - - @Override - public void commitChanges() { - for (Project project : ProjectManager.getInstance().getOpenProjects()) { - WriteAction.run(() -> ((ProjectRootManagerEx)ProjectRootManager.getInstance(project)).makeRootsChange(EmptyRunnable.getInstance(), false, true)); - } - } - - @Override - public boolean isWritable() { - return true; - } - - @NotNull - @Override - public RootProvider getRootProvider() { - return new RootProvider() { - @NotNull - @Override - public String[] getUrls(@NotNull OrderRootType rootType) { - return ContainerUtil.map2Array(getFiles(rootType), String.class, VirtualFile::getUrl); - } - - @NotNull - @Override - public VirtualFile[] getFiles(@NotNull OrderRootType rootType) { - return getRoots(rootType); - } - - @Override - public void addRootSetChangedListener(@NotNull RootSetChangedListener listener) { } - - @Override - public void addRootSetChangedListener(@NotNull RootSetChangedListener listener, @NotNull Disposable parentDisposable) { } - - @Override - public void removeRootSetChangedListener(@NotNull RootSetChangedListener listener) { } - }; - } - - private void throwReadOnly() { - throw new IncorrectOperationException("Can't modify, MockJDK is read-only, consider calling .clone() first"); - } - - @Nullable - @Override - public T getUserData(@NotNull Key key) { - return null; - } - - @Override - public void putUserData(@NotNull Key key, @Nullable T value) { - throwReadOnly(); - } - - @Override - public String toString() { - return "MockSDK[" + myJdkName + "]"; - } - } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java index 83b9b749a4fb..8df4fa8be2ec 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java @@ -24,6 +24,7 @@ import com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens; import com.intellij.psi.search.searches.SuperMethodsSearch; import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Functions; import com.intellij.util.containers.ContainerUtil; @@ -427,13 +428,13 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { private void parseProperties(PsiMethod method, JavaElementArrangementEntry entry) { String propertyName = null; boolean getter = true; - if (PropertyUtil.isSimplePropertyGetter(method)) { + if (PropertyUtilBase.isSimplePropertyGetter(method)) { entry.addModifier(GETTER); - propertyName = PropertyUtil.getPropertyNameByGetter(method); + propertyName = PropertyUtilBase.getPropertyNameByGetter(method); } - else if (PropertyUtil.isSimplePropertySetter(method)) { + else if (PropertyUtilBase.isSimplePropertySetter(method)) { entry.addModifier(SETTER); - propertyName = PropertyUtil.getPropertyNameBySetter(method); + propertyName = PropertyUtilBase.getPropertyNameBySetter(method); getter = false; } diff --git a/java/java-impl/src/com/intellij/psi/impl/beanProperties/BeanProperty.java b/java/java-impl/src/com/intellij/psi/impl/beanProperties/BeanProperty.java index a21a9abae12f..b362aabca520 100644 --- a/java/java-impl/src/com/intellij/psi/impl/beanProperties/BeanProperty.java +++ b/java/java-impl/src/com/intellij/psi/impl/beanProperties/BeanProperty.java @@ -22,6 +22,7 @@ import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiNamedElement; import com.intellij.psi.PsiType; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -51,13 +52,13 @@ public class BeanProperty { @NotNull public String getName() { - final String name = PropertyUtil.getPropertyName(myMethod); + final String name = PropertyUtilBase.getPropertyName(myMethod); return name == null ? "" : name; } @NotNull public PsiType getPropertyType() { - PsiType type = PropertyUtil.getPropertyType(myMethod); + PsiType type = PropertyUtilBase.getPropertyType(myMethod); assert type != null; return type; } @@ -69,29 +70,29 @@ public class BeanProperty { @Nullable public PsiMethod getGetter() { - if (PropertyUtil.isSimplePropertyGetter(myMethod)) { + if (PropertyUtilBase.isSimplePropertyGetter(myMethod)) { return myMethod; } - return PropertyUtil.findPropertyGetter(myMethod.getContainingClass(), getName(), false, true); + return PropertyUtilBase.findPropertyGetter(myMethod.getContainingClass(), getName(), false, true); } @Nullable public PsiMethod getSetter() { - if (PropertyUtil.isSimplePropertySetter(myMethod)) { + if (PropertyUtilBase.isSimplePropertySetter(myMethod)) { return myMethod; } - return PropertyUtil.findPropertySetter(myMethod.getContainingClass(), getName(), false, true); + return PropertyUtilBase.findPropertySetter(myMethod.getContainingClass(), getName(), false, true); } public void setName(String newName) throws IncorrectOperationException { final PsiMethod setter = getSetter(); final PsiMethod getter = getGetter(); if (getter != null) { - final String getterName = PropertyUtil.suggestGetterName(newName, getter.getReturnType()); + final String getterName = PropertyUtilBase.suggestGetterName(newName, getter.getReturnType()); getter.setName(getterName); } if (setter != null) { - final String setterName = PropertyUtil.suggestSetterName(newName); + final String setterName = PropertyUtilBase.suggestSetterName(newName); setter.setName(setterName); } } @@ -103,6 +104,6 @@ public class BeanProperty { @Nullable public static BeanProperty createBeanProperty(@NotNull PsiMethod method) { - return PropertyUtil.isSimplePropertyAccessor(method) ? new BeanProperty(method) : null; + return PropertyUtilBase.isSimplePropertyAccessor(method) ? new BeanProperty(method) : null; } } diff --git a/java/java-impl/src/com/intellij/psi/impl/beanProperties/BeanPropertyElement.java b/java/java-impl/src/com/intellij/psi/impl/beanProperties/BeanPropertyElement.java index 602db4863edd..8842925bfd3e 100644 --- a/java/java-impl/src/com/intellij/psi/impl/beanProperties/BeanPropertyElement.java +++ b/java/java-impl/src/com/intellij/psi/impl/beanProperties/BeanPropertyElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -27,6 +27,7 @@ import com.intellij.psi.meta.PsiMetaData; import com.intellij.psi.meta.PsiMetaOwner; import com.intellij.psi.meta.PsiPresentableMetaData; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -48,7 +49,7 @@ public class BeanPropertyElement extends FakePsiElement implements PsiMetaOwner, @Nullable public PsiType getPropertyType() { - return PropertyUtil.getPropertyType(myMethod); + return PropertyUtilBase.getPropertyType(myMethod); } @NotNull diff --git a/java/java-impl/src/com/intellij/psi/impl/beanProperties/CreateJavaBeanPropertyFix.java b/java/java-impl/src/com/intellij/psi/impl/beanProperties/CreateJavaBeanPropertyFix.java index e435264e8b76..176377c32915 100644 --- a/java/java-impl/src/com/intellij/psi/impl/beanProperties/CreateJavaBeanPropertyFix.java +++ b/java/java-impl/src/com/intellij/psi/impl/beanProperties/CreateJavaBeanPropertyFix.java @@ -28,6 +28,7 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -125,7 +126,7 @@ public class CreateJavaBeanPropertyFix implements LocalQuickFix, IntentionAction private void createSetter(final boolean createField) throws IncorrectOperationException { final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myPsiClass.getProject()).getElementFactory(); - final String methodName = PropertyUtil.suggestSetterName(myPropertyName); + final String methodName = PropertyUtilBase.suggestSetterName(myPropertyName); final String typeName = myType.getCanonicalText(); @NonNls final String text; @@ -154,7 +155,7 @@ public class CreateJavaBeanPropertyFix implements LocalQuickFix, IntentionAction private void createGetter(final boolean createField) throws IncorrectOperationException { final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myPsiClass.getProject()).getElementFactory(); - final String methodName = PropertyUtil.suggestGetterName(myPropertyName, myType); + final String methodName = PropertyUtilBase.suggestGetterName(myPropertyName, myType); final String typeName = myType.getCanonicalText(); @NonNls final String text; PsiClass psiClass = myPsiClass.getElement(); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/MethodPropertyReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/MethodPropertyReference.java index 307d608ddbd8..96a513343cbb 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/MethodPropertyReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/MethodPropertyReference.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -18,6 +18,7 @@ package com.intellij.psi.impl.source.resolve.reference.impl.providers; import com.intellij.psi.*; import com.intellij.psi.jsp.JspSpiUtil; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlAttributeValue; import com.intellij.psi.xml.XmlTag; @@ -89,7 +90,7 @@ public class MethodPropertyReference extends BasicAttributeValueReference { @Override public PsiElement handleElementRename(String _newElementName) throws IncorrectOperationException { - String newElementName = PropertyUtil.getPropertyName(_newElementName); + String newElementName = PropertyUtilBase.getPropertyName(_newElementName); if (newElementName == null) newElementName = _newElementName; return super.handleElementRename(newElementName); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PsiPackageReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PsiPackageReference.java index 658ea9b99826..6a7e652b46d1 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PsiPackageReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PsiPackageReference.java @@ -20,9 +20,12 @@ import com.intellij.codeInsight.daemon.JavaErrorMessages; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; public class PsiPackageReference extends PsiPolyVariantReferenceBase implements EmptyResolveMessageProvider { private final PackageReferenceSet myReferenceSet; @@ -52,7 +55,7 @@ public class PsiPackageReference extends PsiPolyVariantReferenceBase public Object[] getVariants() { Set subPackages = new HashSet<>(); for (PsiPackage psiPackage : getContext()) { - subPackages.addAll(Arrays.asList(psiPackage.getSubPackages(myReferenceSet.getResolveScope()))); + ContainerUtil.addAll(subPackages, psiPackage.getSubPackages(myReferenceSet.getResolveScope())); } return subPackages.toArray(); } diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java index 8860f67e1808..68e0f059fdcb 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java @@ -35,10 +35,7 @@ import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.PsiUtilCore; +import com.intellij.psi.util.*; import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.classMembers.MemberInfoBase; @@ -257,7 +254,7 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { myInnerClass.add(outputField); field = outputField; } else { - field = PropertyUtil.findPropertyField(myInnerClass, name, false); + field = PropertyUtilBase.findPropertyField(myInnerClass, name, false); } LOG.assertTrue(field != null, "i:" + i + "; output variables: " + Arrays.toString(outputVariables) + "; parameters: " + Arrays.toString(getMethod().getParameterList().getParameters()) + "; output field: " + outputField ); myInnerClass.add(GenerateMembersUtil.generateGetterPrototype(field)); diff --git a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java index a100a5dafd31..90f8e168c163 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -24,6 +24,7 @@ import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; @@ -33,10 +34,7 @@ import com.intellij.psi.javadoc.PsiDocTagValue; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.*; import com.intellij.refactoring.MoveDestination; import com.intellij.refactoring.RefactorJBundle; import com.intellij.refactoring.extractclass.usageInfo.*; @@ -602,7 +600,7 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor { if (myGenerateAccessors) { getter = GenerateMembersUtil.suggestGetterName(field); } else { - final PsiMethod fieldGetter = PropertyUtil.findPropertyGetter(sourceClass, field.getName(), false, false); + final PsiMethod fieldGetter = PropertyUtilBase.findPropertyGetter(sourceClass, field.getName(), false, false); if (fieldGetter != null && isInMovedElement(fieldGetter)) { getter = fieldGetter.getName(); } @@ -612,7 +610,7 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor { if (myGenerateAccessors) { setter = GenerateMembersUtil.suggestSetterName(field); } else { - final PsiMethod fieldSetter = PropertyUtil.findPropertySetter(sourceClass, field.getName(), false, false); + final PsiMethod fieldSetter = PropertyUtilBase.findPropertySetter(sourceClass, field.getName(), false, false); if (fieldSetter != null && isInMovedElement(fieldSetter)) { setter = fieldSetter.getName(); } @@ -707,7 +705,7 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor { if (myMoveDestination != null) { directory = myMoveDestination.getTargetDirectory(containingDirectory); } else { - final Module module = ModuleUtil.findModuleForPsiElement(containingFile); + final Module module = ModuleUtilCore.findModuleForPsiElement(containingFile); assert module != null; directory = PackageUtil.findOrCreateDirectoryForPackage(module, newPackageName, containingDirectory, false, true); } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectClassDescriptor.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectClassDescriptor.java index 27d2b503261c..85a82a7ce492 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectClassDescriptor.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectClassDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -26,10 +26,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiTypesUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.psi.util.*; import com.intellij.refactoring.MoveDestination; import com.intellij.refactoring.changeSignature.ParameterInfoImpl; import com.intellij.refactoring.introduceParameterObject.IntroduceParameterObjectClassDescriptor; @@ -207,12 +204,12 @@ public class JavaIntroduceParameterObjectClassDescriptor extends IntroduceParame bean.setField(field); - final PsiMethod getterForField = PropertyUtil.findGetterForField(field); + final PsiMethod getterForField = PropertyUtilBase.findGetterForField(field); if (getterForField != null) { bean.setGetter(getterForField.getName()); } - final PsiMethod setterForField = PropertyUtil.findSetterForField(field); + final PsiMethod setterForField = PropertyUtilBase.findSetterForField(field); if (setterForField != null) { bean.setSetter(setterForField.getName()); } diff --git a/java/java-impl/src/com/intellij/refactoring/removemiddleman/RemoveMiddlemanProcessor.java b/java/java-impl/src/com/intellij/refactoring/removemiddleman/RemoveMiddlemanProcessor.java index 0695ad6d34f1..aae5bd5cdcb8 100644 --- a/java/java-impl/src/com/intellij/refactoring/removemiddleman/RemoveMiddlemanProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/removemiddleman/RemoveMiddlemanProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -22,6 +22,7 @@ import com.intellij.psi.*; import com.intellij.psi.presentation.java.SymbolPresentationUtil; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.refactoring.RefactorJBundle; import com.intellij.refactoring.removemiddleman.usageInfo.DeleteMethod; import com.intellij.refactoring.removemiddleman.usageInfo.InlineDelegatingCall; @@ -48,9 +49,9 @@ public class RemoveMiddlemanProcessor extends FixableUsagesRefactoringProcessor super(field.getProject()); this.field = field; containingClass = field.getContainingClass(); - final String propertyName = PropertyUtil.suggestPropertyName(field); + final String propertyName = PropertyUtilBase.suggestPropertyName(field); final boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); - getter = PropertyUtil.findPropertyGetter(containingClass, propertyName, isStatic, false); + getter = PropertyUtilBase.findPropertyGetter(containingClass, propertyName, isStatic, false); myDelegateMethodInfos = memberInfos; } diff --git a/java/java-impl/src/com/intellij/refactoring/rename/BeanPropertyRenameHandler.java b/java/java-impl/src/com/intellij/refactoring/rename/BeanPropertyRenameHandler.java index 368309f84005..577b9392a0bc 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/BeanPropertyRenameHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/BeanPropertyRenameHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -26,6 +26,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.impl.beanProperties.BeanProperty; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.refactoring.RenameRefactoring; import com.intellij.refactoring.openapi.impl.JavaRenameRefactoringImpl; import org.jetbrains.annotations.Contract; @@ -91,7 +92,7 @@ public abstract class BeanPropertyRenameHandler implements RenameHandler { final PsiElement setterSubstitutor = substituteElementToRename(setter, editor); if (setterSubstitutor != null) { if (setterSubstitutor == setter) { - rename.addElement(setterSubstitutor, PropertyUtil.suggestSetterName(newName)); + rename.addElement(setterSubstitutor, PropertyUtilBase.suggestSetterName(newName)); } else { rename.addElement(setterSubstitutor, newName); @@ -110,7 +111,7 @@ public abstract class BeanPropertyRenameHandler implements RenameHandler { final PsiElement getterSubstitutor = substituteElementToRename(getter, editor); if (getterSubstitutor != null) { if (getterSubstitutor == getter) { - rename.addElement(getterSubstitutor, PropertyUtil.suggestGetterName(newName, getter.getReturnType())); + rename.addElement(getterSubstitutor, PropertyUtilBase.suggestGetterName(newName, getter.getReturnType())); } else { rename.addElement(getterSubstitutor, newName); diff --git a/java/java-impl/src/com/intellij/refactoring/rename/JavaNameSuggestionProvider.java b/java/java-impl/src/com/intellij/refactoring/rename/JavaNameSuggestionProvider.java index fb4eedd640b5..87fdf3a194b4 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/JavaNameSuggestionProvider.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/JavaNameSuggestionProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -23,6 +23,7 @@ import com.intellij.psi.codeStyle.NameUtil; import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.usageView.UsageViewUtil; import com.intellij.util.ArrayUtil; @@ -48,7 +49,7 @@ public class JavaNameSuggestionProvider implements NameSuggestionProvider { if (nameSuggestionContextParent instanceof PsiParameterList) { final PsiElement parentOfParent = nameSuggestionContextParent.getParent(); if (parentOfParent instanceof PsiMethod) { - final String propName = PropertyUtil.getPropertyName((PsiMethod)parentOfParent); + final String propName = PropertyUtilBase.getPropertyName((PsiMethod)parentOfParent); if (propName != null) { parameterName = propName; } diff --git a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaVariableProcessor.java b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaVariableProcessor.java index 507068fb4624..30c0218c56c2 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaVariableProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaVariableProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -28,6 +28,7 @@ import com.intellij.psi.controlFlow.ControlFlowUtil; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.HelpID; @@ -148,14 +149,14 @@ public class RenameJavaVariableProcessor extends RenameJavaMemberProcessor { Project project = field.getProject(); final JavaCodeStyleManager manager = JavaCodeStyleManager.getInstance(project); - final String propertyName = PropertyUtil.suggestPropertyName(field, field.getName()); - final String newPropertyName = PropertyUtil.suggestPropertyName(field, newName); + final String propertyName = PropertyUtilBase.suggestPropertyName(field, field.getName()); + final String newPropertyName = PropertyUtilBase.suggestPropertyName(field, newName); boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); PsiMethod[] getters = GetterSetterPrototypeProvider.findGetters(aClass, propertyName, isStatic); - PsiMethod setter = PropertyUtil.findPropertySetter(aClass, propertyName, isStatic, false); + PsiMethod setter = PropertyUtilBase.findPropertySetter(aClass, propertyName, isStatic, false); boolean shouldRenameSetterParameter = false; @@ -170,7 +171,7 @@ public class RenameJavaVariableProcessor extends RenameJavaMemberProcessor { String getterId = null; if (newGetterName == null) { getterId = getter.getName(); - newGetterName = PropertyUtil.suggestGetterName(newPropertyName, field.getType(), getterId); + newGetterName = PropertyUtilBase.suggestGetterName(newPropertyName, field.getType(), getterId); } if (newGetterName.equals(getterId)) { continue; @@ -192,7 +193,7 @@ public class RenameJavaVariableProcessor extends RenameJavaMemberProcessor { String newSetterName = ""; if (setter != null) { - newSetterName = PropertyUtil.suggestSetterName(newPropertyName); + newSetterName = PropertyUtilBase.suggestSetterName(newPropertyName); final String newSetterParameterName = manager.propertyNameToVariableName(newPropertyName, VariableKind.PARAMETER); if (newSetterName.equals(setter.getName())) { setter = null; @@ -222,7 +223,7 @@ public class RenameJavaVariableProcessor extends RenameJavaMemberProcessor { for (PsiMethod getter : getters) { String newGetterName = GetterSetterPrototypeProvider.suggestNewGetterName(propertyName, newPropertyName, getter); if (newGetterName == null) { - newGetterName = PropertyUtil.suggestGetterName(newPropertyName, field.getType(), getter.getName()); + newGetterName = PropertyUtilBase.suggestGetterName(newPropertyName, field.getType(), getter.getName()); } addOverriddenAndImplemented(getter, newGetterName, null, propertyName, manager, allRenames); } diff --git a/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ParameterData.java b/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ParameterData.java index 5479ca9ecc02..b31cc605d279 100644 --- a/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ParameterData.java +++ b/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ParameterData.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -22,6 +22,7 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.refactoring.util.RefactoringUtil; import java.util.Map; @@ -87,7 +88,7 @@ public class ParameterData { parameterData = new ParameterData(paramName, parameter.getType()); parameterData.setFieldName(styleManager.suggestVariableName(VariableKind.FIELD, uniqueParamName, null, parameter.getType()).names[0]); - parameterData.setSetterName(PropertyUtil.suggestSetterName(uniqueParamName, setterPrefix)); + parameterData.setSetterName(PropertyUtilBase.suggestSetterName(uniqueParamName, setterPrefix)); result.put(uniqueParamName, parameterData); } diff --git a/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderDialog.java b/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderDialog.java index fb8fb60d5d72..f14c7ebf5450 100644 --- a/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderDialog.java @@ -37,6 +37,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.refactoring.PackageWrapper; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.move.moveClassesOrPackages.DestinationFolderComboBox; @@ -154,7 +155,7 @@ public class ReplaceConstructorWithBuilderDialog extends RefactoringDialog { final ParameterData data = myParametersMap.get(paramName); paramName = data.getParamName(); final String propertyName = javaCodeStyleManager.variableNameToPropertyName(paramName, VariableKind.PARAMETER); - data.setSetterName(PropertyUtil.suggestSetterName(propertyName, setterPrefix)); + data.setSetterName(PropertyUtilBase.suggestSetterName(propertyName, setterPrefix)); } myTable.revalidate(); myTable.repaint(); diff --git a/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderProcessor.java b/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderProcessor.java index c33335187fd8..3ab38492196f 100644 --- a/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -19,6 +19,7 @@ import com.intellij.ide.highlighter.JavaFileType; import com.intellij.ide.util.PackageUtil; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Ref; @@ -29,10 +30,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.psi.util.*; import com.intellij.refactoring.MoveDestination; import com.intellij.refactoring.replaceConstructorWithBuilder.usageInfo.ReplaceConstructorWithSettersChainInfo; import com.intellij.refactoring.util.FixableUsageInfo; @@ -118,7 +116,7 @@ public class ReplaceConstructorWithBuilderProcessor extends FixableUsagesRefacto if (myMoveDestination != null) { directory = myMoveDestination.getTargetDirectory(containingDirectory); } else { - final Module module = ModuleUtil.findModuleForPsiElement(containingFile); + final Module module = ModuleUtilCore.findModuleForPsiElement(containingFile); assert module != null; directory = PackageUtil.findOrCreateDirectoryForPackage(module, myPackageName, containingDirectory, true, true); } @@ -178,7 +176,7 @@ public class ReplaceConstructorWithBuilderProcessor extends FixableUsagesRefacto } } if (setter == null) { - setter = PropertyUtil.generateSetterPrototype(field, builderClass, true); + setter = PropertyUtilBase.generateSetterPrototype(field, builderClass, true); final PsiIdentifier nameIdentifier = setter.getNameIdentifier(); assert nameIdentifier != null; nameIdentifier.replace(myElementFactory.createIdentifier(parameterData.getSetterName())); @@ -217,7 +215,7 @@ public class ReplaceConstructorWithBuilderProcessor extends FixableUsagesRefacto private void fixSetterReturnType(PsiClass builderClass, PsiField field, PsiMethod method) { if (PsiUtil.resolveClassInType(method.getReturnType()) != builderClass) { final PsiCodeBlock body = method.getBody(); - final PsiCodeBlock generatedBody = PropertyUtil.generateSetterPrototype(field, builderClass, true).getBody(); + final PsiCodeBlock generatedBody = PropertyUtilBase.generateSetterPrototype(field, builderClass, true).getBody(); assert body != null; assert generatedBody != null; body.replace(generatedBody); diff --git a/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java b/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java index 4e501efbd4cd..964ee645f568 100644 --- a/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java @@ -35,10 +35,7 @@ import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.MethodSignatureUtil; -import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.*; import com.intellij.refactoring.JavaRefactoringSettings; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.changeSignature.inCallers.AbstractJavaMemberCallerChooser; @@ -233,7 +230,7 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { getters = validGetters.isEmpty() ? null : validGetters.toArray(new PsiMethod[validGetters.size()]); } - PsiMethod setter = PropertyUtil.findPropertySetter(aClass, propertyName, isStatic, false); + PsiMethod setter = PropertyUtilBase.findPropertySetter(aClass, propertyName, isStatic, false); if (allElementsToDelete.contains(setter) || setter != null && !setter.isPhysical()) setter = null; if (askUser && (getters != null || setter != null)) { final String message = @@ -928,7 +925,7 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { return true; }); - PsiMethod setterPrototype = PropertyUtil.generateSetterPrototype(psiField, psiField.getContainingClass()); + PsiMethod setterPrototype = PropertyUtilBase.generateSetterPrototype(psiField, psiField.getContainingClass()); PsiParameter setterParameter = setterPrototype.getParameterList().getParameters()[0]; for (PsiParameter parameter : parameters) { PsiElement scope = parameter.getDeclarationScope(); diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java index 26ee4011e98a..d10ab603419d 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java @@ -705,7 +705,8 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { PsiField field = (PsiField) resolved; final NavigatablePsiElement containingMethod = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, PsiLambdaExpression.class); if (containingMethod instanceof PsiMethod) { - final PsiMethod setter = PropertyUtil.findPropertySetter(field.getContainingClass(), field.getName(), field.hasModifierProperty(PsiModifier.STATIC), false); + final PsiMethod setter = PropertyUtilBase + .findPropertySetter(field.getContainingClass(), field.getName(), field.hasModifierProperty(PsiModifier.STATIC), false); if (containingMethod.isEquivalentTo(setter)) { return true; } diff --git a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java index 155686ea8938..7c1dc1fd0004 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java @@ -1401,14 +1401,14 @@ public class RefactoringUtil { } private static void collectTypeParametersInDependencies(Condition filter, Set used) { - HashSet typeParametersInDependencies = new HashSet<>(); - for (PsiTypeParameter parameter : used) { - collectTypeParameters(typeParametersInDependencies, parameter, filter); - } - typeParametersInDependencies.removeAll(used); - if (!typeParametersInDependencies.isEmpty()) { - collectTypeParametersInDependencies(filter, typeParametersInDependencies); - used.addAll(typeParametersInDependencies); + Stack toProcess = new Stack<>(); + toProcess.addAll(used); + while (!toProcess.isEmpty()) { + PsiTypeParameter parameter = toProcess.pop(); + HashSet dependencies = new HashSet<>(); + collectTypeParameters(dependencies, parameter, param -> filter.value(param) && !used.contains(param)); + used.addAll(dependencies); + toProcess.addAll(dependencies); } } diff --git a/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueProcessor.java b/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueProcessor.java index e87ddf3a3994..1a85b1e5fe06 100644 --- a/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -31,6 +31,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.MoveDestination; @@ -110,7 +111,7 @@ public class WrapReturnValueProcessor extends FixableUsagesRefactoringProcessor return unboxedType.getCanonicalText() + "Value()"; } - final PsiMethod getter = PropertyUtil.findGetterForField(myDelegateField); + final PsiMethod getter = PropertyUtilBase.findGetterForField(myDelegateField); return getter != null ? getter.getName() : ""; } return ""; diff --git a/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java b/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java index 3a17ca5cc22b..dfcf46afc401 100644 --- a/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java +++ b/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java @@ -59,6 +59,7 @@ import com.intellij.testIntegration.TestFramework; import com.intellij.testIntegration.TestIntegrationUtils; import com.intellij.ui.*; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.JBUI; import org.jetbrains.annotations.NotNull; @@ -355,8 +356,7 @@ public class CreateTestDialog extends DialogWrapper { final DefaultComboBoxModel model = (DefaultComboBoxModel)myLibrariesCombo.getModel(); - final List descriptors = new ArrayList<>(); - descriptors.addAll(Arrays.asList(Extensions.getExtensions(TestFramework.EXTENSION_NAME))); + final List descriptors = new SmartList<>(Extensions.getExtensions(TestFramework.EXTENSION_NAME)); descriptors.sort((d1, d2) -> Comparing.compare(d1.getName(), d2.getName())); for (final TestFramework descriptor : descriptors) { diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java index 09eff7dbd55a..786401480ac4 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java @@ -147,10 +147,10 @@ public class JavaOverridingMethodsSearcher implements QueryExecutor 0) { PsiMethod found = MethodSignatureUtil.findMethodBySuperSignature(inheritor, getSuperSignature(inheritor, methodContainingClass, method), false); diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/SimpleAccessorReferenceSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/SimpleAccessorReferenceSearcher.java index 4d939ddd3e1b..71cd62b649b9 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/SimpleAccessorReferenceSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/SimpleAccessorReferenceSearcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -27,6 +27,7 @@ import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.UsageSearchContext; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; @@ -47,7 +48,7 @@ public class SimpleAccessorReferenceSearcher extends QueryExecutorBase modListInfo = parseModifierList(builder); ReferenceParser.TypeInfo typeInfo = null; if (typed) { - int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD; - if (ellipsis) flags |= ReferenceParser.ELLIPSIS; - if (disjunctiveType) flags |= ReferenceParser.DISJUNCTIONS; + int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD | typeFlags; typeInfo = myParser.getReferenceParser().parseTypeInfo(builder, flags); if (typeInfo == null) { diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/ReferenceParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/ReferenceParser.java index 1471eaaff3c8..58856a1e8502 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/ReferenceParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/ReferenceParser.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.daemon.JavaErrorMessages; import com.intellij.lang.PsiBuilder; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.JavaTokenType; +import com.intellij.psi.PsiKeyword; import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.tree.IElementType; @@ -39,6 +40,7 @@ public class ReferenceParser { public static final int DISJUNCTIONS = 0x10; public static final int CONJUNCTIONS = 0x20; public static final int INCOMPLETE_ANNO = 0x40; + public static final int VAR_TYPE = 0x80; public static class TypeInfo { public boolean isPrimitive; @@ -94,12 +96,22 @@ public class ReferenceParser { private TypeInfo parseTypeInfo(PsiBuilder builder, int flags, boolean badWildcard) { if (builder.getTokenType() == null) return null; - final TypeInfo typeInfo = new TypeInfo(); + TypeInfo typeInfo = new TypeInfo(); PsiBuilder.Marker type = builder.mark(); PsiBuilder.Marker anno = myParser.getDeclarationParser().parseAnnotations(builder); - final IElementType tokenType = builder.getTokenType(); + IElementType tokenType = builder.getTokenType(); + if (tokenType == JavaTokenType.IDENTIFIER && + isSet(flags, VAR_TYPE) && + PsiKeyword.VAR.equals(builder.getTokenText()) && + getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_X)) { + builder.remapCurrentToken(tokenType = JavaTokenType.VAR_KEYWORD); + } + else if (tokenType == JavaTokenType.VAR_KEYWORD && !isSet(flags, VAR_TYPE)) { + builder.remapCurrentToken(tokenType = JavaTokenType.IDENTIFIER); + } + if (expect(builder, ElementType.PRIMITIVE_TYPE_BIT_SET)) { typeInfo.isPrimitive = true; } @@ -117,6 +129,12 @@ public class ReferenceParser { else if (tokenType == JavaTokenType.IDENTIFIER) { parseJavaCodeReference(builder, isSet(flags, EAT_LAST_DOT), true, false, false, false, isSet(flags, DIAMONDS), typeInfo); } + else if (tokenType == JavaTokenType.VAR_KEYWORD) { + builder.advanceLexer(); + type.done(JavaElementType.TYPE); + typeInfo.marker = type; + return typeInfo; + } else if (isSet(flags, DIAMONDS) && tokenType == JavaTokenType.GT) { if (anno == null) { emptyElement(builder, JavaElementType.DIAMOND_TYPE); @@ -144,7 +162,7 @@ public class ReferenceParser { type.done(JavaElementType.TYPE); myParser.getDeclarationParser().parseAnnotations(builder); - final PsiBuilder.Marker bracket = builder.mark(); + PsiBuilder.Marker bracket = builder.mark(); if (!expect(builder, JavaTokenType.LBRACKET)) { bracket.drop(); break; diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/StatementParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/StatementParser.java index 4c96f87178f3..0bcebeb31479 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/StatementParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/StatementParser.java @@ -319,7 +319,7 @@ public class StatementParser { } final PsiBuilder.Marker afterParenth = builder.mark(); - final PsiBuilder.Marker param = myParser.getDeclarationParser().parseParameter(builder, false, false); + final PsiBuilder.Marker param = myParser.getDeclarationParser().parseParameter(builder, false, false, true); if (param == null || exprType(param) != JavaElementType.PARAMETER || builder.getTokenType() != JavaTokenType.COLON) { afterParenth.rollbackTo(); return parseForLoopFromInitializer(builder, statement); @@ -616,7 +616,7 @@ public class StatementParser { return false; } - final PsiBuilder.Marker param = myParser.getDeclarationParser().parseParameter(builder, false, true); + final PsiBuilder.Marker param = myParser.getDeclarationParser().parseParameter(builder, false, true, false); if (param == null) { error(builder, JavaErrorMessages.message("expected.parameter")); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java index f8c923862f8f..37c90b0806b6 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java @@ -62,7 +62,7 @@ public class PsiJavaParserFacadeImpl implements PsiJavaParserFacade { private static final JavaParserUtil.ParserWrapper PARAMETER = new JavaParserUtil.ParserWrapper() { @Override public void parse(final PsiBuilder builder) { - JavaParser.INSTANCE.getDeclarationParser().parseParameter(builder, true, false); + JavaParser.INSTANCE.getDeclarationParser().parseParameter(builder, true, false, false); } }; @@ -76,8 +76,8 @@ public class PsiJavaParserFacadeImpl implements PsiJavaParserFacade { private static final JavaParserUtil.ParserWrapper TYPE = new JavaParserUtil.ParserWrapper() { @Override public void parse(final PsiBuilder builder) { - JavaParser.INSTANCE.getReferenceParser().parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.ELLIPSIS | - ReferenceParser.WILDCARD | ReferenceParser.DISJUNCTIONS); + int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.ELLIPSIS | ReferenceParser.WILDCARD | ReferenceParser.DISJUNCTIONS | ReferenceParser.VAR_TYPE; + JavaParser.INSTANCE.getReferenceParser().parseType(builder, flags); } }; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsClassImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsClassImpl.java index 1dd7b6591b97..d79094064755 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsClassImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsClassImpl.java @@ -61,7 +61,7 @@ public class ClsClassImpl extends ClsMemberImpl> implements PsiE @NotNull public PsiElement[] getChildren() { List children = ContainerUtil.newArrayList(); - ContainerUtil.addAll(children, getChildren(getDocComment(), getModifierList(), getNameIdentifier(), getExtendsList(), getImplementsList())); + ContainerUtil.addAll(children, getChildren(getDocComment(), getModifierListInternal(), getNameIdentifier(), getExtendsList(), getImplementsList())); ContainerUtil.addAll(children, getOwnFields()); ContainerUtil.addAll(children, getOwnMethods()); ContainerUtil.addAll(children, getOwnInnerClasses()); @@ -84,23 +84,37 @@ public class ClsClassImpl extends ClsMemberImpl> implements PsiE public String getQualifiedName() { return getStub().getQualifiedName(); } - - boolean isAnonymousOrLocalClass() { + + private boolean isLocalClass() { PsiClassStub stub = getStub(); - return !(stub instanceof PsiClassStubImpl) || - ((PsiClassStubImpl)stub).isAnonymousInner() || + return stub instanceof PsiClassStubImpl && ((PsiClassStubImpl)stub).isLocalClassInner(); } + private boolean isAnonymousClass() { + PsiClassStub stub = getStub(); + return stub instanceof PsiClassStubImpl && + ((PsiClassStubImpl)stub).isAnonymousInner(); + } + + private boolean isAnonymousOrLocalClass() { + return isAnonymousClass() || isLocalClass(); + } + @Override - @NotNull + @Nullable public PsiModifierList getModifierList() { + if (isAnonymousClass()) return null; + return getModifierListInternal(); + } + + private PsiModifierList getModifierListInternal() { return getStub().findChildStubByType(JavaStubElementTypes.MODIFIER_LIST).getPsi(); } @Override public boolean hasModifierProperty(@NotNull String name) { - return getModifierList().hasModifierProperty(name); + return getModifierListInternal().hasModifierProperty(name); } @Override @@ -348,7 +362,7 @@ public class ClsClassImpl extends ClsMemberImpl> implements PsiE public void appendMirrorText(final int indentLevel, @NotNull @NonNls final StringBuilder buffer) { appendText(getDocComment(), indentLevel, buffer, NEXT_LINE); - appendText(getModifierList(), indentLevel, buffer); + appendText(getModifierListInternal(), indentLevel, buffer); buffer.append(isEnum() ? "enum " : isAnnotationType() ? "@interface " : isInterface() ? "interface " : "class "); appendText(getNameIdentifier(), indentLevel, buffer, " "); appendText(getTypeParameterList(), indentLevel, buffer, " "); @@ -435,7 +449,8 @@ public class ClsClassImpl extends ClsMemberImpl> implements PsiE setMirrorIfPresent(getDocComment(), mirror.getDocComment()); - setMirror(getModifierList(), mirror.getModifierList()); + PsiModifierList modifierList = getModifierList(); + if (modifierList != null) setMirror(modifierList, mirror.getModifierList()); setMirror(getNameIdentifier(), mirror.getNameIdentifier()); setMirror(getTypeParameterList(), mirror.getTypeParameterList()); setMirror(getExtendsList(), mirror.getExtendsList()); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java index 523d070d19a5..5f7f2c9c80fe 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java @@ -94,6 +94,15 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl String text = child.getText(); type = annotations.isEmpty() ? PsiJavaParserFacadeImpl.getPrimitiveType(text) : new PsiPrimitiveType(text, createProvider(annotations)); } + else if (PsiUtil.isJavaToken(child, JavaTokenType.VAR_KEYWORD)) { + assert type == null : this; + for (PsiElement e = this; e != null; e = e.getNextSibling()) { + if (e instanceof PsiExpression) { + type = ((PsiExpression)e).getType(); + break; + } + } + } else if (child instanceof PsiJavaCodeReferenceElement) { assert type == null : this; type = new PsiClassReferenceType(getReferenceComputable((PsiJavaCodeReferenceElement)child), null, createProvider(annotations)); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/ElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/ElementType.java index f504d7c65281..f7d14ca03561 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/ElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/ElementType.java @@ -36,7 +36,7 @@ public interface ElementType extends JavaTokenType, JavaDocTokenType, JavaElemen SWITCH_KEYWORD, SYNCHRONIZED_KEYWORD, THIS_KEYWORD, THROW_KEYWORD, THROWS_KEYWORD, TRANSIENT_KEYWORD, TRY_KEYWORD, VOID_KEYWORD, VOLATILE_KEYWORD, WHILE_KEYWORD, OPEN_KEYWORD, MODULE_KEYWORD, REQUIRES_KEYWORD, EXPORTS_KEYWORD, OPENS_KEYWORD, USES_KEYWORD, PROVIDES_KEYWORD, - TRANSITIVE_KEYWORD, TO_KEYWORD, WITH_KEYWORD); + TRANSITIVE_KEYWORD, TO_KEYWORD, WITH_KEYWORD, VAR_KEYWORD); TokenSet LITERAL_BIT_SET = TokenSet.create(TRUE_KEYWORD, FALSE_KEYWORD, NULL_KEYWORD); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java index 48537ada61fd..03e3aac370a6 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java @@ -244,10 +244,8 @@ public interface JavaElementType { private final JavaParserUtil.ParserWrapper myParser = new JavaParserUtil.ParserWrapper() { @Override public void parse(final PsiBuilder builder) { - JavaParser.INSTANCE.getReferenceParser().parseType(builder, ReferenceParser.EAT_LAST_DOT | - ReferenceParser.ELLIPSIS | - ReferenceParser.WILDCARD | - myFlags); + int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.ELLIPSIS | ReferenceParser.WILDCARD | myFlags; + JavaParser.INSTANCE.getReferenceParser().parseType(builder, flags); } }; diff --git a/java/java-tests/testData/codeInsight/completeStatement/IfWithoutParentheses.java b/java/java-tests/testData/codeInsight/completeStatement/IfWithoutParentheses.java new file mode 100644 index 000000000000..eac3d7a16a23 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completeStatement/IfWithoutParentheses.java @@ -0,0 +1,6 @@ + +class Foo { + public void foo() { + if 1 > 2 + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completeStatement/IfWithoutParentheses_after.java b/java/java-tests/testData/codeInsight/completeStatement/IfWithoutParentheses_after.java new file mode 100644 index 000000000000..a2ca520e169f --- /dev/null +++ b/java/java-tests/testData/codeInsight/completeStatement/IfWithoutParentheses_after.java @@ -0,0 +1,8 @@ + +class Foo { + public void foo() { + if (1 > 2) { + + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/keywords/finalInCompleteCatch.java b/java/java-tests/testData/codeInsight/completion/keywords/finalInCompleteCatch.java new file mode 100644 index 000000000000..b907799d7799 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/keywords/finalInCompleteCatch.java @@ -0,0 +1,9 @@ +public class X { + { + try { + + } catch ( AssertionError error) { + + } + } +} diff --git a/java/java-tests/testData/codeInsight/completion/keywords/finalInCompleteTryWithResources.java b/java/java-tests/testData/codeInsight/completion/keywords/finalInCompleteTryWithResources.java new file mode 100644 index 000000000000..72ccabe6f4a3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/keywords/finalInCompleteTryWithResources.java @@ -0,0 +1,5 @@ +public class Util { + void foo() { + try ( Type var = val) + } +} diff --git a/java/java-tests/testData/codeInsight/completion/keywords/returnInRussian.java b/java/java-tests/testData/codeInsight/completion/keywords/returnInRussian.java new file mode 100644 index 000000000000..ab34191503ae --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/keywords/returnInRussian.java @@ -0,0 +1,5 @@ +public class Util { + int goo() { + куку + } +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/NoDuplicateInCast.java b/java/java-tests/testData/codeInsight/completion/normal/NoDuplicateInCast.java new file mode 100644 index 000000000000..10b937f946b2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/NoDuplicateInCast.java @@ -0,0 +1,11 @@ +class X { + void foo(Object o){ + if (o instanceof Foo) { + ((Foo) o).bar(); + } + } + + class Foo { + void bar() {} + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/PreferLambdaOverGenericGetter.java b/java/java-tests/testData/codeInsight/completion/smartType/PreferLambdaOverGenericGetter.java new file mode 100644 index 000000000000..4421fd3667eb --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/PreferLambdaOverGenericGetter.java @@ -0,0 +1,10 @@ +class Foo { + void processImports(java.util.function.Predicate pr) {} + + { + processImports(); + } + + static T getSomeGenericValue(T t) {} + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/PreferVariableToLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/PreferVariableToLambda.java new file mode 100644 index 000000000000..a1d1673828ba --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/PreferVariableToLambda.java @@ -0,0 +1,11 @@ +interface I { + void foo(String out); +} + +class Foo { + I output; + + { + I r = out + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/simplifyForEach/beforeCompilationCtor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/simplifyForEach/beforeCompilationCtor.java new file mode 100644 index 000000000000..ab1c59ed889a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/simplifyForEach/beforeCompilationCtor.java @@ -0,0 +1,12 @@ +// "Avoid mutation using Stream API 'count()' operation" "false" + +import java.util.*; + +public class Main { + // EA-107550 - NPE: SimplifyForEachInspection.extractLambdaFromForEach + void test() { + int x = 0; + class X {X(Runnable r) {}} + new X(() -> x++); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamToLoop/afterArraySlice.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamToLoop/afterArraySlice.java new file mode 100644 index 000000000000..6096ceba9bbc --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamToLoop/afterArraySlice.java @@ -0,0 +1,13 @@ +// "Replace Stream API chain with loop" "true" + +import java.util.Arrays; + +public class Test { + public static void test(String[] arr) { + int bound = arr.length - 1; + for (int i = 1; i < bound; i++) { + String s = arr[i]; + System.out.println(s); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamToLoop/beforeArraySlice.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamToLoop/beforeArraySlice.java new file mode 100644 index 000000000000..853dabd4c91e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamToLoop/beforeArraySlice.java @@ -0,0 +1,9 @@ +// "Replace Stream API chain with loop" "true" + +import java.util.Arrays; + +public class Test { + public static void test(String[] arr) { + Arrays.stream(arr, 1, arr.length - 1).forEach(System.out::println); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollBreak.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollBreak.java new file mode 100644 index 000000000000..b0ba681d1014 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollBreak.java @@ -0,0 +1,19 @@ +// "Unroll loop" "true" +class Test { + void test() { + if (!(Math.random() > 0.5)) { + System.out.println((Object) "one"); + if (!(Math.random() > 0.5)) { + System.out.println((Object) 1); + if (!(Math.random() > 0.5)) { + System.out.println((Object) 1.0); + if (!(Math.random() > 0.5)) { + System.out.println((Object) 1.0f); + } + } + } + } + } + + void foo(boolean b) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollBreakMultiple.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollBreakMultiple.java new file mode 100644 index 000000000000..35ac031146ad --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollBreakMultiple.java @@ -0,0 +1,25 @@ +// "Unroll loop" "true" +class Test { + void test(String s1, String s2, String s3) { + if (s1.length() <= 5) { + System.out.println("Long string: " + s1); + if (s1.length() <= 20) { + System.out.println("Very long string: " + s1); + if (s2.length() <= 5) { + System.out.println("Long string: " + s2); + if (s2.length() <= 20) { + System.out.println("Very long string: " + s2); + if (s3.length() <= 5) { + System.out.println("Long string: " + s3); + if (s3.length() <= 20) { + System.out.println("Very long string: " + s3); + } + } + } + } + } + } + } + + void foo(boolean b) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollBreakNoBraces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollBreakNoBraces.java new file mode 100644 index 000000000000..b187a26dae22 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollBreakNoBraces.java @@ -0,0 +1,14 @@ +// "Unroll loop" "true" +class Test { + void test(String s1, String s2, String s3) { + if ((i += s1.length()) <= 10) { + if ((i += s2.length()) <= 10) { + if ((i += s3.length()) <= 10) { + } + } + } + System.out.println(i); + } + + void foo(boolean b) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollListJava9.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollListJava9.java new file mode 100644 index 000000000000..1b6f3ebc77fb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollListJava9.java @@ -0,0 +1,19 @@ +// "Unroll loop" "true" +import java.util.*; + +class Test { + void test() { + if (!"foo".isEmpty()) { + System.out.println("foo"); + } + if (!"bar".isEmpty()) { + System.out.println("bar"); + } + if (!"baz".isEmpty()) { + System.out.println("baz"); + } + if (!"".isEmpty()) { + System.out.println(""); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollListOneJava9.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollListOneJava9.java new file mode 100644 index 000000000000..6337da2ee8f8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollListOneJava9.java @@ -0,0 +1,10 @@ +// "Unroll loop" "true" +import java.util.*; + +class Test { + void test() { + if (!"foo".isEmpty()) { + System.out.println("foo"); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollNoBraces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollNoBraces.java new file mode 100644 index 000000000000..9527ef8d105a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollNoBraces.java @@ -0,0 +1,11 @@ +// "Unroll loop" "true" +import java.util.Arrays; + +class Test { + void test() { + System.out.println("foo"); + System.out.println("bar"); + } + + void foo(boolean b) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollSingleton.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollSingleton.java new file mode 100644 index 000000000000..7e71a0a601f5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/afterUnrollSingleton.java @@ -0,0 +1,10 @@ +// "Unroll loop" "true" +import java.util.*; + +class Test { + void test() { + if (!"xyz".isEmpty()) { + System.out.println("xyz"); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreak.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreak.java index f078e3c89202..099bb21eb2ac 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreak.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreak.java @@ -1,4 +1,4 @@ -// "Unroll loop" "false" +// "Unroll loop" "true" class Test { void test() { for(Object x : new Object[] {"one", 1, 1.0, 1.0f}) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreakDeeper.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreakDeeper.java new file mode 100644 index 000000000000..27fa41346ea4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreakDeeper.java @@ -0,0 +1,15 @@ +// "Unroll loop" "false" +class Test { + void test(String s1, String s2, String s3) { + for(String s : new String[] {s1, s2, s3}) { + if (!s.isEmpty()) { + if(s.length() > 5) break; + } + System.out.println("Long string: "+s); + if(s.length() > 20) break; + System.out.println("Very long string: "+s); + } + } + + void foo(boolean b) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreakMultiple.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreakMultiple.java new file mode 100644 index 000000000000..5e0e81985378 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreakMultiple.java @@ -0,0 +1,13 @@ +// "Unroll loop" "true" +class Test { + void test(String s1, String s2, String s3) { + for(String s : new String[] {s1, s2, s3}) { + if(s.length() > 5) break; + System.out.println("Long string: "+s); + if(s.length() > 20) break; + System.out.println("Very long string: "+s); + } + } + + void foo(boolean b) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreakNoBraces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreakNoBraces.java new file mode 100644 index 000000000000..56501d74fe58 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollBreakNoBraces.java @@ -0,0 +1,10 @@ +// "Unroll loop" "true" +class Test { + void test(String s1, String s2, String s3) { + for(String s : new String[] {s1, s2, s3}) + if((i+=s.length()) > 10) break; + System.out.println(i); + } + + void foo(boolean b) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollListArray.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollListArray.java new file mode 100644 index 000000000000..6d2662f6a796 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollListArray.java @@ -0,0 +1,12 @@ +// "Unroll loop" "false" +import java.util.*; + +class Test { + void test(String[] data) { + for(String s : Arrays.asList(data)) { + if(!s.isEmpty()) { + System.out.println(s); + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollListJava9.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollListJava9.java new file mode 100644 index 000000000000..1e15d8a5d038 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollListJava9.java @@ -0,0 +1,12 @@ +// "Unroll loop" "true" +import java.util.*; + +class Test { + void test() { + for(String s : List.of("foo", "bar", "baz", "")) { + if(!s.isEmpty()) { + System.out.println(s); + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollListOneJava9.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollListOneJava9.java new file mode 100644 index 000000000000..e70d5216d71c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollListOneJava9.java @@ -0,0 +1,12 @@ +// "Unroll loop" "true" +import java.util.*; + +class Test { + void test() { + for(String s : List.of("foo")) { + if(!s.isEmpty()) { + System.out.println(s); + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollNoBraces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollNoBraces.java new file mode 100644 index 000000000000..33e72ea029db --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollNoBraces.java @@ -0,0 +1,10 @@ +// "Unroll loop" "true" +import java.util.Arrays; + +class Test { + void test() { + for(String s : Arrays.asList("foo", "bar")) System.out.println(s); + } + + void foo(boolean b) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollSingleton.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollSingleton.java new file mode 100644 index 000000000000..c9da24336c0b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollSingleton.java @@ -0,0 +1,12 @@ +// "Unroll loop" "true" +import java.util.*; + +class Test { + void test() { + for(String s : Collections.singleton("xyz")) { + if(!s.isEmpty()) { + System.out.println(s); + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollWritesVar.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollWritesVar.java new file mode 100644 index 000000000000..e01c49a1ea1e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop/beforeUnrollWritesVar.java @@ -0,0 +1,13 @@ +// "Unroll loop" "false" +class Test { + void test() { + for(int x : new int[]{1, 2, 3}) { + System.out.println(x); + x = 6; + x++; + System.out.println(x); + } + } + + void foo(boolean b) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/opt/notNullMethodCall.java b/java/java-tests/testData/codeInsight/template/postfix/templates/opt/notNullMethodCall.java new file mode 100644 index 000000000000..f874970148fd --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/opt/notNullMethodCall.java @@ -0,0 +1,12 @@ +import org.jetbrains.annotations.NotNull; + +class Test { + @NotNull + String foo() { + return ""; + } + + void m() { + foo().opt + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/opt/notNullMethodCall_after.java b/java/java-tests/testData/codeInsight/template/postfix/templates/opt/notNullMethodCall_after.java new file mode 100644 index 000000000000..e5331c237e5e --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/opt/notNullMethodCall_after.java @@ -0,0 +1,12 @@ +import org.jetbrains.annotations.NotNull; + +class Test { + @NotNull + String foo() { + return ""; + } + + void m() { + java.util.Optional.of(foo()) + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/stream/notAvailable.java b/java/java-tests/testData/codeInsight/template/postfix/templates/stream/notAvailable.java new file mode 100644 index 000000000000..1ea9a888d7e1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/stream/notAvailable.java @@ -0,0 +1,5 @@ +class Test { + void m(byte[] ss) { + ss.stream + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/stream/notAvailable_after.java b/java/java-tests/testData/codeInsight/template/postfix/templates/stream/notAvailable_after.java new file mode 100644 index 000000000000..492e02bfe8fd --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/stream/notAvailable_after.java @@ -0,0 +1,5 @@ +class Test { + void m(byte[] ss) { + ss.stream + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/LambdaInlining.java b/java/java-tests/testData/inspection/dataFlow/fixture/LambdaInlining.java index 4bc09bca8205..aff0995ad755 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/LambdaInlining.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/LambdaInlining.java @@ -27,4 +27,20 @@ public class LambdaInlining { System.out.println("oops"); } } + + void testLambdaTryFinally() { + int x = ((IntSupplier)() -> { + try { + return 10; + } finally { + return 20; + } + }).getAsInt(); + if(x == 30) { + System.out.println("oops"); + } + if(x < 30) { + System.out.println("always"); + } + } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/StreamComparatorInlining.java b/java/java-tests/testData/inspection/dataFlow/fixture/StreamComparatorInlining.java new file mode 100644 index 000000000000..36a50f657407 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/StreamComparatorInlining.java @@ -0,0 +1,49 @@ +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.stream.*; + +public class StreamComparatorInlining { + static class Holder { + @Nullable String nullable; + + @Nullable String getNullable() { + return nullable; + } + } + + @Nullable String process(String s) { + return s.isEmpty() ? null : s; + } + + void testMinMax(List list) { + list.stream().map(this::process).max(Comparator.naturalOrder()); + list.stream().map(this::process).max(Comparator.nullsFirst(Comparator.naturalOrder())); + list.stream().map(this::process).max(Comparator.nullsFirst(Comparator.comparing(String::length))); + list.stream().map(this::process).min(Comparator.nullsLast(Comparator.comparing(String::length))); + list.stream().map(this::process).min(Comparator.comparing(String::length)); + list.stream().map(this::process).min(Comparator.comparing(String::length).reversed()); + } + + void testSorted(List list) { + list.stream().sorted(Comparator.comparing(this::process, Comparator.reverseOrder())).collect(Collectors.toList()); + list.stream().sorted(Comparator.comparing(this::process)).collect(Collectors.toList()); + list.stream().sorted(Comparator.comparing(this::process, Comparator.nullsFirst(Comparator.naturalOrder()))).collect(Collectors.toList()); + list.stream().map(this::process).sorted(Comparator.comparing(String::length)).collect(Collectors.toList()); + list.stream().map(this::process).sorted().collect(Collectors.toList()); + list.stream().map(this::process).sorted(String::compareToIgnoreCase).collect(Collectors.toList()); + list.stream().map(this::process).sorted(String.CASE_INSENSITIVE_ORDER).collect(Collectors.toList()); + } + + void testSortedCheck(List holders) { + holders.stream().sorted(Comparator.comparing(h -> h.nullable)).toArray(); + holders.stream().filter(h -> h.nullable != null).sorted(Comparator.comparing(h -> h.nullable)).toArray(); + + holders.stream().sorted(Comparator.comparing(h -> h.getNullable())).toArray(); + holders.stream().filter(h -> h.getNullable() != null).sorted(Comparator.comparing(h -> h.getNullable())).toArray(); + + holders.stream().sorted(Comparator.comparing(Holder::getNullable)).toArray(); + holders.stream().filter(h -> h.getNullable() != null).sorted(Comparator.comparing(Holder::getNullable)).toArray(); + } +} diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/StreamInlining.java b/java/java-tests/testData/inspection/dataFlow/fixture/StreamInlining.java index d48cf36358b6..f38d46c725a6 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/StreamInlining.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/StreamInlining.java @@ -38,11 +38,6 @@ public class StreamInlining { static class Holder { Object obj; - @Nullable String nullable; - - @Nullable String getNullable() { - return nullable; - } } int hash(List holders) { @@ -136,38 +131,4 @@ public class StreamInlining { Stream.generate(() -> Optional.of("xyz")).filter(Optional::isPresent).forEach(System.out::println); LongStream.generate(() -> 5).limit(10).filter(x -> x > 6).forEach(s -> System.out.println(s)); } - - @Nullable String process(String s) { - return s.isEmpty() ? null : s; - } - - void testMinMax(List list) { - list.stream().map(this::process).max(Comparator.naturalOrder()); - list.stream().map(this::process).max(Comparator.nullsFirst(Comparator.naturalOrder())); - list.stream().map(this::process).max(Comparator.nullsFirst(Comparator.comparing(String::length))); - list.stream().map(this::process).min(Comparator.nullsLast(Comparator.comparing(String::length))); - list.stream().map(this::process).min(Comparator.comparing(String::length)); - list.stream().map(this::process).min(Comparator.comparing(String::length).reversed()); - } - - void testSorted(List list) { - list.stream().sorted(Comparator.comparing(this::process, Comparator.reverseOrder())).collect(Collectors.toList()); - list.stream().sorted(Comparator.comparing(this::process)).collect(Collectors.toList()); - list.stream().sorted(Comparator.comparing(this::process, Comparator.nullsFirst(Comparator.naturalOrder()))).collect(Collectors.toList()); - list.stream().map(this::process).sorted(Comparator.comparing(String::length)).collect(Collectors.toList()); - list.stream().map(this::process).sorted().collect(Collectors.toList()); - list.stream().map(this::process).sorted(String::compareToIgnoreCase).collect(Collectors.toList()); - list.stream().map(this::process).sorted(String.CASE_INSENSITIVE_ORDER).collect(Collectors.toList()); - } - - void testSortedCheck(List holders) { - holders.stream().sorted(Comparator.comparing(h -> h.nullable)).toArray(); - holders.stream().filter(h -> h.nullable != null).sorted(Comparator.comparing(h -> h.nullable)).toArray(); - - holders.stream().sorted(Comparator.comparing(h -> h.getNullable())).toArray(); - holders.stream().filter(h -> h.getNullable() != null).sorted(Comparator.comparing(h -> h.getNullable())).toArray(); - - holders.stream().sorted(Comparator.comparing(Holder::getNullable)).toArray(); - holders.stream().filter(h -> h.getNullable() != null).sorted(Comparator.comparing(Holder::getNullable)).toArray(); - } } diff --git a/java/java-tests/testData/psi/parser-partial/statements/ForIncomplete10.txt b/java/java-tests/testData/psi/parser-partial/statements/ForIncomplete10.txt new file mode 100644 index 000000000000..652024111714 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/ForIncomplete10.txt @@ -0,0 +1,16 @@ +PsiJavaFile:ForIncomplete10.java + PsiForStatement + PsiKeyword:for('for') + PsiJavaToken:LPARENTH('(') + PsiDeclarationStatement + PsiLocalVariable:x + PsiModifierList: + + PsiTypeElement:var + PsiKeyword:var('var') + PsiWhiteSpace(' ') + PsiIdentifier:x('x') + PsiErrorElement:';' expected + + PsiErrorElement:';' expected + \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/ForNormal2.txt b/java/java-tests/testData/psi/parser-partial/statements/ForNormal2.txt new file mode 100644 index 000000000000..59c8e2d141f6 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/ForNormal2.txt @@ -0,0 +1,24 @@ +PsiJavaFile:ForNormal2.java + PsiForStatement + PsiKeyword:for('for') + PsiJavaToken:LPARENTH('(') + PsiDeclarationStatement + PsiLocalVariable:x + PsiModifierList: + + PsiTypeElement:var + PsiKeyword:var('var') + PsiWhiteSpace(' ') + PsiIdentifier:x('x') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:SEMICOLON(';') + PsiJavaToken:RPARENTH(')') + PsiWhiteSpace(' ') + PsiEmptyStatement + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/ForNormal3.txt b/java/java-tests/testData/psi/parser-partial/statements/ForNormal3.txt new file mode 100644 index 000000000000..defbfafbafd8 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/ForNormal3.txt @@ -0,0 +1,22 @@ +PsiJavaFile:ForNormal3.java + PsiForeachStatement + PsiKeyword:for('for') + PsiJavaToken:LPARENTH('(') + PsiParameter:x + PsiModifierList: + + PsiTypeElement:var + PsiKeyword:var('var') + PsiWhiteSpace(' ') + PsiIdentifier:x('x') + PsiWhiteSpace(' ') + PsiJavaToken:COLON(':') + PsiWhiteSpace(' ') + PsiReferenceExpression:list + PsiReferenceParameterList + + PsiIdentifier:list('list') + PsiJavaToken:RPARENTH(')') + PsiWhiteSpace(' ') + PsiEmptyStatement + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/LocalVar3.txt b/java/java-tests/testData/psi/parser-partial/statements/LocalVar3.txt new file mode 100644 index 000000000000..3ad05715f320 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/LocalVar3.txt @@ -0,0 +1,10 @@ +PsiJavaFile:LocalVar3.java + PsiDeclarationStatement + PsiLocalVariable:x + PsiModifierList: + + PsiTypeElement:var + PsiKeyword:var('var') + PsiWhiteSpace(' ') + PsiIdentifier:x('x') + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/LocalVar4.txt b/java/java-tests/testData/psi/parser-partial/statements/LocalVar4.txt new file mode 100644 index 000000000000..b3b2154111f3 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/LocalVar4.txt @@ -0,0 +1,11 @@ +PsiJavaFile:LocalVar4.java + PsiDeclarationStatement + PsiLocalVariable:x + PsiModifierList:final + PsiKeyword:final('final') + PsiWhiteSpace(' ') + PsiTypeElement:var + PsiKeyword:var('var') + PsiWhiteSpace(' ') + PsiIdentifier:x('x') + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/LocalVar5.txt b/java/java-tests/testData/psi/parser-partial/statements/LocalVar5.txt new file mode 100644 index 000000000000..53da4881f962 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/LocalVar5.txt @@ -0,0 +1,18 @@ +PsiJavaFile:LocalVar5.java + PsiDeclarationStatement + PsiLocalVariable:x + PsiModifierList:@A + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:A + PsiIdentifier:A('A') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiWhiteSpace(' ') + PsiTypeElement:var + PsiKeyword:var('var') + PsiWhiteSpace(' ') + PsiIdentifier:x('x') + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete19.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete19.txt new file mode 100644 index 000000000000..1bf1d05e595c --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete19.txt @@ -0,0 +1,18 @@ +PsiJavaFile:TryIncomplete19.java + PsiTryStatement + PsiKeyword:try('try') + PsiResourceList:(var r) + PsiJavaToken:LPARENTH('(') + PsiResourceVariable:r + PsiModifierList: + + PsiTypeElement:var + PsiKeyword:var('var') + PsiWhiteSpace(' ') + PsiIdentifier:r('r') + PsiErrorElement:'=' expected + + PsiJavaToken:RPARENTH(')') + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryNormal13.txt b/java/java-tests/testData/psi/parser-partial/statements/TryNormal13.txt new file mode 100644 index 000000000000..a439c6100e6e --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/TryNormal13.txt @@ -0,0 +1,21 @@ +PsiJavaFile:TryNormal13.java + PsiTryStatement + PsiKeyword:try('try') + PsiResourceList:(var r = null) + PsiJavaToken:LPARENTH('(') + PsiResourceVariable:r + PsiModifierList: + + PsiTypeElement:var + PsiKeyword:var('var') + PsiWhiteSpace(' ') + PsiIdentifier:r('r') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:null + PsiJavaToken:NULL_KEYWORD('null') + PsiJavaToken:RPARENTH(')') + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/TypeParamsListWithRecursiveDependencies.java b/java/java-tests/testData/refactoring/extractMethod/TypeParamsListWithRecursiveDependencies.java new file mode 100644 index 000000000000..34c63819d3cd --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/TypeParamsListWithRecursiveDependencies.java @@ -0,0 +1,6 @@ +class Test { + + void f(C c) { + System.out.println(c); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/TypeParamsListWithRecursiveDependencies_after.java b/java/java-tests/testData/refactoring/extractMethod/TypeParamsListWithRecursiveDependencies_after.java new file mode 100644 index 000000000000..a7aaae5d3ed8 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/TypeParamsListWithRecursiveDependencies_after.java @@ -0,0 +1,10 @@ +class Test { + + void f(C c) { + newMethod(c); + } + + private void newMethod(C c) { + System.out.println(c); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionProfileTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionProfileTest.java index 7bb8e8940107..b15119516f8f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionProfileTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionProfileTest.java @@ -32,6 +32,8 @@ import com.intellij.testFramework.InspectionsKt; import com.intellij.testFramework.LightIdeaTestCase; import com.intellij.util.JdomKt; import com.intellij.util.SmartList; +import com.siyeh.ig.naming.ClassNamingConvention; +import com.siyeh.ig.naming.NewClassNamingConventionInspection; import org.jdom.Element; import org.jdom.JDOMException; import org.jetbrains.annotations.NotNull; @@ -222,42 +224,28 @@ public class InspectionProfileTest extends LightIdeaTestCase { //settings to merge - final Element unusedProfile = JdomKt.loadElement("\n" + - " "); + String serialized = + "\n" + + " "; + final Element unusedProfile = JdomKt.loadElement(serialized); profile.readExternal(unusedProfile); profile.getModifiableModel().commit(); - assertEquals("\n" + - " ", serialize(profile)); + assertEquals(serialized, serialize(profile)); //make them default profile = createProfile(new InspectionProfileImpl("foo")); @@ -302,6 +290,101 @@ public class InspectionProfileTest extends LightIdeaTestCase { assertThat(importedProfile.writeScheme()).isEqualTo(mergedElement); } + + public void testMergeNamingConventions() throws Exception { + //no specific settings + final Element element = JdomKt.loadElement("\n" + + " "); + InspectionProfileImpl profile = createProfile(new InspectionProfileImpl("foo")); + profile.readExternal(element); + profile.getModifiableModel().commit(); + assertThat(profile.writeScheme()).isEqualTo(element); + + String unchanged = "\n" + + " "; + final Element allEnabledProfile = JdomKt.loadElement(unchanged); + profile.readExternal(allEnabledProfile); + profile.getModifiableModel().commit(); + assertEquals(unchanged, serialize(profile)); + + //make them default + profile = createProfile(new InspectionProfileImpl("foo")); + String customSettingsText = "\n" + + " "; + profile.readExternal(JdomKt.loadElement(customSettingsText)); + assertEquals(customSettingsText, serialize(profile)); + InspectionToolWrapper wrapper = profile.getInspectionTool("NewClassNamingConvention", getProject()); + assertNotNull(wrapper); + NewClassNamingConventionInspection tool = (NewClassNamingConventionInspection)wrapper.getTool(); + assertEquals(256, tool.getNamingConventionBean("AnnotationNamingConvention").m_maxLength); + assertEquals(1, tool.getNamingConventionBean("EnumeratedClassNamingConvention").m_minLength); + assertTrue(profile.isToolEnabled(HighlightDisplayKey.find("NewClassNamingConvention"), null)); + assertFalse(tool.isConventionEnabled("TypeParameterNamingConvention")); + assertFalse(tool.isConventionEnabled(ClassNamingConvention.CLASS_NAMING_CONVENTION_SHORT_NAME)); + + Element toImportElement = profile.writeScheme(); + final InspectionProfileImpl importedProfile = + InspectionProfileSchemesPanel.importInspectionProfile(toImportElement, getApplicationProfileManager(), getProject()); + + //check merged + Element mergedElement = JdomKt.loadElement(customSettingsText); + profile = createProfile(new InspectionProfileImpl("foo")); + profile.readExternal(mergedElement); + profile.getModifiableModel().commit(); + assertThat(profile.writeScheme()).isEqualTo(mergedElement); + + assertThat(importedProfile.writeScheme()).isEqualTo(mergedElement); + } public void testStoredMemberVisibility() throws Exception { InspectionProfileImpl profile = createProfile(new InspectionProfileImpl("foo")); diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/CompleteStatementTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/CompleteStatementTest.java index 32d7f7472fa0..97157989428a 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/CompleteStatementTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/CompleteStatementTest.java @@ -84,6 +84,7 @@ public class CompleteStatementTest extends EditorActionTestCase { public void testForIncrementExpressionAndBody() { doTest(); } public void testEmptyBeforeReturn() { doTest(); } public void testIf() { doTest(); } + public void testIfWithoutParentheses() { doTest(); } public void testBeforeStatement() { doTest(); } public void testTry1() { doTest(); } public void testInsideResourceVariable() { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/CompletionHintsTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/CompletionHintsTest.java index 4d85f0afa7bd..51637736e17f 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/CompletionHintsTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/CompletionHintsTest.java @@ -610,6 +610,18 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase { checkHintContents(null); } + public void testPopupAfterCaretMovesOutsideOfParenthesis() throws Exception { + configureJava("class C { void m() { System.getPro } }"); + complete("getProperty(String key, String def)"); + waitForAllAsyncStuff(); + checkHintContents("@NotNull String"); + left(); + left(); + left(); + waitForAllAsyncStuff(); + checkHintContents(null); + } + private void checkResult(String text) { myFixture.checkResult(text); } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/KeywordCompletionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/KeywordCompletionTest.java index 2e26d7d90996..e90a9aafa7ee 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/KeywordCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/KeywordCompletionTest.java @@ -132,13 +132,16 @@ public class KeywordCompletionTest extends LightCompletionTestCase { public void testAbstractInInterface() { doTest(1, "abstract"); } public void testCharInAnnotatedParameter() { doTest(1, "char"); } public void testReturnInTernary() { doTest(1, "return"); } + public void testReturnInRussian() { doTest(1, "return"); } public void testFinalAfterParameterAnno() { doTest(2, "final", "float", "class"); } public void testFinalAfterParameterAnno2() { doTest(2, "final", "float", "class"); } public void testFinalAfterCase() { doTest(3, "final", "float", "class"); } public void testNoCaseInsideWhileInSwitch() { doTest(0, "case", "default"); } public void testFinalInCatch() { doTest(1, "final"); } public void testFinalInIncompleteCatch() { doTest(1, "final"); } + public void testFinalInCompleteCatch() { doTest(1, "final"); } public void testFinalInTryWithResources() { doTest(1, "final", "float", "class"); } + public void testFinalInCompleteTryWithResources() { doTest(1, "final", "float", "class"); } public void testFinalInLambda() { doTest(2, "final", "float"); } public void testNoFinalAfterTryBody() { doTest(1, "final", "finally"); } public void testClassInMethod() { doTest(2, "class", "char"); } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/Normal8CompletionTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/Normal8CompletionTest.groovy index ae0af6127049..5a86e5bc8502 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/Normal8CompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/Normal8CompletionTest.groovy @@ -106,8 +106,8 @@ class Test { void bar(int i) {} }""" def items = myFixture.completeBasic() - assert LookupElementPresentation.renderElement(items[0]).itemText == 'x -> {}' - assert items.find { LookupElementPresentation.renderElement(it).itemText.contains('this::bar') } != null + assert items.any { LookupElementPresentation.renderElement(it).itemText == 'x -> {}' } + assert items.any { LookupElementPresentation.renderElement(it).itemText.contains('this::bar') } } void "test suggest receiver method reference"() { @@ -301,6 +301,11 @@ class Test88 { checkResultByFileName() } + void testPreferVariableToLambda() { + configureByTestName() + myFixture.assertPreferredCompletionItems 0, 'output', 'out -> ' + } + private checkResultByFileName() { checkResultByFile(getTestName(false) + "_after.java") } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy index 58b6ba2a6a2e..de50be614956 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy @@ -1826,4 +1826,20 @@ class Bar { assert myFixture.lookupElementStrings == ['web'] } + void testLocalClassPresentation() { + def cls = myFixture.addFileToProject('foo/Bar.java', """package foo; +class Bar {{ + class Local {} + Lox +}}""") + myFixture.configureFromExistingVirtualFile(cls.containingFile.virtualFile) + def item = myFixture.completeBasic()[0] + assert LookupElementPresentation.renderElement(item).tailText.contains('local class') + } + + void testNoDuplicateInCast() { + configure() + assert myFixture.lookupElementStrings == null + } + } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartType18CompletionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartType18CompletionTest.java index 9b34349f5730..e6d2792176ea 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartType18CompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartType18CompletionTest.java @@ -258,4 +258,8 @@ public void testConvertToObjectStream() { public void testNewHashMapTypeArguments() { doTest(false); } public void testNewMapTypeArguments() { doTest(false); } + public void testPreferLambdaOverGenericGetter() { + configureByTestName(); + myFixture.assertPreferredCompletionItems(0, "isEmpty", "s -> ", "getSomeGenericValue"); + } } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/JavadocHtmlLintInspectionTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/JavadocHtmlLintInspectionTest.kt index 8da63e0eedef..d02e4087647e 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/JavadocHtmlLintInspectionTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/JavadocHtmlLintInspectionTest.kt @@ -16,6 +16,9 @@ package com.intellij.java.codeInsight.daemon import com.intellij.codeInspection.javaDoc.JavadocHtmlLintInspection +import com.intellij.openapi.projectRoots.JavaSdk +import com.intellij.openapi.projectRoots.impl.JavaSdkImpl +import com.intellij.openapi.roots.ModuleRootModificationUtil import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import com.intellij.util.PathUtil @@ -27,6 +30,9 @@ class JavadocHtmlLintInspectionTest : LightCodeInsightFixtureTestCase() { val javaHome = System.getProperty("java.home") val jdkHome = if (javaHome.endsWith("jre")) PathUtil.getParentPath(javaHome) else javaHome VfsRootAccess.allowRootAccess(myFixture.testRootDisposable, jdkHome) + + val jdk = (JavaSdk.getInstance() as JavaSdkImpl).createMockJdk("java version \"1.8.0\"", System.getProperty("java.home"), true) + ModuleRootModificationUtil.setModuleSdk(myModule, jdk); } fun testNoComment() = doTest("class C { }") diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/UnrollLoopActionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/UnrollLoopActionTest.java index d69cc6541089..faae721a0282 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/UnrollLoopActionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/UnrollLoopActionTest.java @@ -16,11 +16,20 @@ package com.intellij.java.codeInsight.intention; import com.intellij.codeInsight.daemon.LightIntentionActionTestCase; +import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import org.jetbrains.annotations.NotNull; public class UnrollLoopActionTest extends LightIntentionActionTestCase { public void test() { doAllTests(); } + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return LightCodeInsightFixtureTestCase.JAVA_9; + } + @Override protected String getBasePath() { return "/codeInsight/daemonCodeAnalyzer/quickFix/unrollLoop"; diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/template/postfix/templates/OptionalPostfixTemplateTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/template/postfix/templates/OptionalPostfixTemplateTest.java index de78213fb37e..e86e9e559c74 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/template/postfix/templates/OptionalPostfixTemplateTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/template/postfix/templates/OptionalPostfixTemplateTest.java @@ -80,6 +80,12 @@ public class OptionalPostfixTemplateTest extends PostfixTemplateTestCase { public void testLong() { doTest(); } + + public void testNotNullMethodCall() { + myFixture.addClass("package org.jetbrains.annotations;" + + "public @interface NotNull {}"); + doTest(); + } public void testDoNotExpandOnJavaLess8() { IdeaTestUtil.setModuleLanguageLevel(myModule, LanguageLevel.JDK_1_6, myFixture.getTestRootDisposable()); diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/template/postfix/templates/StreamPostfixTemplateTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/template/postfix/templates/StreamPostfixTemplateTest.java index 0a29265e4c1b..405c682fc189 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/template/postfix/templates/StreamPostfixTemplateTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/template/postfix/templates/StreamPostfixTemplateTest.java @@ -57,6 +57,10 @@ public class StreamPostfixTemplateTest extends PostfixTemplateTestCase { doTest(); } + public void testNotAvailable() { + doTest(); + } + public void testDoNotExpandOnJavaLess8() { IdeaTestUtil.setModuleLanguageLevel(myModule, LanguageLevel.JDK_1_6, myFixture.getTestRootDisposable()); doTest(); diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java index c38437578c7f..7cd89c5f7851 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java @@ -195,6 +195,7 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase { doTest(); } public void testStreamInlining() { doTest(); } + public void testStreamComparatorInlining() { doTest(); } public void testStreamKnownSource() { doTest(); } public void testMethodVsExpressionTypeAnnotationConflict() { diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/RedundantCast15Test.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/RedundantCast15Test.java index 27ec322f5628..116dee125e3a 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/RedundantCast15Test.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/RedundantCast15Test.java @@ -87,7 +87,6 @@ public class RedundantCast15Test extends InspectionTestCase { public void testIgnore() { final RedundantCastInspection castInspection = new RedundantCastInspection(); - castInspection.IGNORE_ANNOTATED_METHODS = true; castInspection.IGNORE_SUSPICIOUS_METHOD_CALLS = true; final LocalInspectionToolWrapper tool = new LocalInspectionToolWrapper(castInspection); doTest("redundantCast/generics/" + getTestName(false), tool, "java 1.5"); diff --git a/java/java-tests/testSrc/com/intellij/java/navigation/ChooseByNameHddTest.groovy b/java/java-tests/testSrc/com/intellij/java/navigation/ChooseByNameHddTest.groovy index 25d8b341a8ba..c0815c001c06 100644 --- a/java/java-tests/testSrc/com/intellij/java/navigation/ChooseByNameHddTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/navigation/ChooseByNameHddTest.groovy @@ -18,8 +18,6 @@ package com.intellij.java.navigation import com.intellij.ide.util.gotoByName.ChooseByNamePopup import com.intellij.ide.util.gotoByName.GotoClassModel2 import com.intellij.ide.util.gotoByName.GotoFileModel -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.ReadAction import com.intellij.openapi.module.ModuleUtilCore import com.intellij.openapi.module.StdModuleTypes import com.intellij.openapi.roots.ModuleRootModificationUtil @@ -27,7 +25,6 @@ import com.intellij.openapi.util.io.FileUtil import com.intellij.psi.PsiElement import com.intellij.testFramework.PsiTestUtil import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase -import org.jetbrains.annotations.NotNull /** * @author peter */ @@ -37,15 +34,12 @@ class ChooseByNameHddTest extends JavaCodeInsightFixtureTestCase { def vFile = psiFile.virtualFile def path = vFile.path - ApplicationManager.application.runReadAction { - def model = new GotoFileModel(project) - def popup = ChooseByNamePopup.createPopup(project, model, (PsiElement)null) - assert ChooseByNameTest.calcPopupElements(popup, path) == [psiFile] - assert ChooseByNameTest.calcPopupElements(popup, FileUtil.toSystemDependentName(path)) == [psiFile] - assert ChooseByNameTest.calcPopupElements(popup, vFile.parent.path) == [psiFile.containingDirectory] - assert ChooseByNameTest.calcPopupElements(popup, path + ':0') == [psiFile] - popup.close(false) - } + def popup = ChooseByNamePopup.createPopup(project, new GotoFileModel(project), (PsiElement)null) + assert ChooseByNameTest.calcPopupElements(popup, path) == [psiFile] + assert ChooseByNameTest.calcPopupElements(popup, FileUtil.toSystemDependentName(path)) == [psiFile] + assert ChooseByNameTest.calcPopupElements(popup, vFile.parent.path) == [psiFile.containingDirectory] + assert ChooseByNameTest.calcPopupElements(popup, path + ':0') == [psiFile] + popup.close(false) } void "test prefer same-named classes visible in current module"() { @@ -57,7 +51,7 @@ class ChooseByNameHddTest extends JavaCodeInsightFixtureTestCase { (0..moduleCount-1).each { myFixture.addFileToProject("mod$it/Foo.java", "class Foo {}") } def place = myFixture.addClass("class A {}") - def popup = ReadAction.compute { ChooseByNamePopup.createPopup(project, new GotoClassModel2(project), place) } + def popup = ChooseByNamePopup.createPopup(project, new GotoClassModel2(project), place) def resultModules = ChooseByNameTest.calcPopupElements(popup, 'Foo').collect { ModuleUtilCore.findModuleForPsiElement(it as PsiElement).name } @@ -69,20 +63,11 @@ class ChooseByNameHddTest extends JavaCodeInsightFixtureTestCase { PsiTestUtil.addModule(project, StdModuleTypes.JAVA, 'm1', myFixture.tempDirFixture.findOrCreateDir("foo")) PsiTestUtil.addModule(project, StdModuleTypes.JAVA, 'm2', myFixture.tempDirFixture.findOrCreateDir("foo/bar")) def file = myFixture.addFileToProject('foo/bar/goo/doo.txt', '') - def popup = ReadAction.compute { ChooseByNamePopup.createPopup(project, new GotoFileModel(project), file) } + def popup = ChooseByNamePopup.createPopup(project, new GotoFileModel(project), file) assert ChooseByNameTest.calcPopupElements(popup, "doo", false) == [file] assert ChooseByNameTest.calcPopupElements(popup, "goo/doo", false) == [file] assert ChooseByNameTest.calcPopupElements(popup, "bar/goo/doo", false) == [file] assert ChooseByNameTest.calcPopupElements(popup, "foo/bar/goo/doo", false) == [file] } - @Override - protected boolean runInDispatchThread() { - return false - } - - @Override - protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception { - runnable.run() - } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/navigation/ChooseByNameTest.groovy b/java/java-tests/testSrc/com/intellij/java/navigation/ChooseByNameTest.groovy index 40fc43129ccc..7f963b7a2143 100644 --- a/java/java-tests/testSrc/com/intellij/java/navigation/ChooseByNameTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/navigation/ChooseByNameTest.groovy @@ -19,23 +19,19 @@ import com.intellij.codeInsight.JavaProjectCodeInsightSettings import com.intellij.ide.util.gotoByName.* import com.intellij.lang.java.JavaLanguage import com.intellij.openapi.Disposable -import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ModalityState -import com.intellij.openapi.application.ReadAction -import com.intellij.openapi.util.Computable import com.intellij.openapi.util.Disposer import com.intellij.psi.CommonClassNames +import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.search.ProjectScope +import com.intellij.testFramework.PlatformTestUtil import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import com.intellij.util.Consumer import com.intellij.util.concurrency.Semaphore -import org.jetbrains.annotations.NotNull import org.jetbrains.plugins.groovy.lang.psi.GroovyFile -import javax.swing.* - import static com.intellij.testFramework.EdtTestUtil.runInEdtAndWait /** * @author peter @@ -106,13 +102,11 @@ class Impl extends Intf { def elements = getPopupElements(new GotoSymbolModel2(project), "xxx") - ReadAction.run { - assert intf.findMethodsByName('xxx1', false)[0] in elements - assert intf.findMethodsByName('xxx2', false)[0] in elements + assert intf.findMethodsByName('xxx1', false)[0] in elements + assert intf.findMethodsByName('xxx2', false)[0] in elements - assert impl.findMethodsByName('xxx3', false)[0] in elements - assert !(impl.findMethodsByName('xxx1', false)[0] in elements) - } + assert impl.findMethodsByName('xxx3', false)[0] in elements + assert !(impl.findMethodsByName('xxx1', false)[0] in elements) } void "test disprefer underscore"() { @@ -161,12 +155,12 @@ class Intf { assert elements == files } - void "test middle matching for directories"() { + void "test middle matching for files and directories"() { def fooIndex = myFixture.addFileToProject("foo/index.html", "foo") def ooIndex = myFixture.addFileToProject("oo/index.html", "oo") def fooBarIndex = myFixture.addFileToProject("foo/bar/index.html", "foo bar") - def elements = getPopupElements(new GotoFileModel(project), "oo/index") - assert elements == [ooIndex, fooIndex, fooBarIndex] + assert getPopupElements(new GotoFileModel(project), "oo/index") == [ooIndex, fooIndex, fooBarIndex] + assert getPopupElements(new GotoFileModel(project), "ndex.html") == [fooIndex, ooIndex, fooBarIndex] } void "test prefer files from current directory"() { @@ -229,7 +223,7 @@ class Intf { void "test find method by qualified name"() { def clazz = myFixture.addClass("package foo.bar; class Goo { void zzzZzz() {} }") - def method = ApplicationManager.application.runReadAction( { clazz.methods[0] } as Computable) + def method = clazz.methods[0] assert getPopupElements(new GotoSymbolModel2(project), 'zzzZzz') == [method] assert getPopupElements(new GotoSymbolModel2(project), 'goo.zzzZzz') == [method] assert getPopupElements(new GotoSymbolModel2(project), 'foo.bar.goo.zzzZzz') == [method] @@ -261,7 +255,7 @@ class Intf { void "test dollar"() { def bar = myFixture.addClass("package foo; class Bar { class Foo {} }") - def foo = ApplicationManager.application.runReadAction( { bar.innerClasses[0] } as Computable) + def foo = bar.innerClasses[0] myFixture.addClass("package goo; class Goo { }") assert getPopupElements(new GotoClassModel2(project), 'Bar$Foo') == [foo] assert getPopupElements(new GotoClassModel2(project), 'foo.Bar$Foo') == [foo] @@ -295,9 +289,7 @@ class Intf { } private static filterJavaItems(List items) { - return ApplicationManager.application.runReadAction ({ - return items.findAll { it instanceof PsiElement && it.language == JavaLanguage.INSTANCE } - } as Computable) + return items.findAll { it instanceof PsiElement && it.language == JavaLanguage.INSTANCE } } void "test super method in jdk"() { @@ -370,7 +362,7 @@ class Intf { void "test out-of-project-content files"() { def scope = ProjectScope.getAllScope(project) - def file = ReadAction.compute { myFixture.javaFacade.findClass(CommonClassNames.JAVA_LANG_OBJECT, scope).containingFile } + def file = myFixture.javaFacade.findClass(CommonClassNames.JAVA_LANG_OBJECT, scope).containingFile def elements = getPopupElements(new GotoFileModel(project), "Object.class", true) assert file in elements } @@ -403,21 +395,35 @@ class Intf { assert calcPopupElements(popup, "somefb\\index.html") == [someFbFile] } + void "test fix keyboard layout"() { + assert (getPopupElements(new GotoClassModel2(project), 'Ыекштп')[0] as PsiClass).name == 'String' + assert (getPopupElements(new GotoSymbolModel2(project), 'Ыекштп')[0] as PsiClass).name == 'String' + assert (getPopupElements(new GotoFileModel(project), 'Ыекштп')[0] as PsiFile).name == 'String.class' + } + + void "test prefer exact case match"() { + def upper = myFixture.addClass("class SOMECLASS {}") + def camel = myFixture.addClass("class SomeClass {}") + assert getPopupElements(new GotoClassModel2(project), 'SomeClass') == [camel, upper] + assert getPopupElements(new GotoFileModel(project), 'SomeClass.java') == [camel.containingFile, upper.containingFile] + } + private List getPopupElements(ChooseByNameModel model, String text, boolean checkboxState = false) { return calcPopupElements(createPopup(model), text, checkboxState) } static ArrayList calcPopupElements(ChooseByNamePopup popup, String text, boolean checkboxState = false) { List elements = ['empty'] - def semaphore = new Semaphore() - semaphore.down() - SwingUtilities.invokeLater { - popup.scheduleCalcElements(text, checkboxState, ModalityState.NON_MODAL, { set -> - elements = set as List - semaphore.up() - } as Consumer>) + def semaphore = new Semaphore(1) + popup.scheduleCalcElements(text, checkboxState, ModalityState.NON_MODAL, { set -> + elements = set as List + semaphore.up() + } as Consumer>) + def start = System.currentTimeMillis() + while (!semaphore.waitFor(10) && System.currentTimeMillis() - start < 10_000_000) { + PlatformTestUtil.dispatchAllInvocationEventsInIdeEventQueue() } - if (!semaphore.waitFor(10_000_000)) { + if (!semaphore.waitFor(10)) { printThreadDump() fail() } @@ -436,13 +442,4 @@ class Intf { myPopup } - @Override - protected boolean runInDispatchThread() { - return false - } - - @Override - protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception { - runnable.run() - } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/navigation/GotoActionTest.groovy b/java/java-tests/testSrc/com/intellij/java/navigation/GotoActionTest.groovy index 8ace828314e9..dbea493f596c 100644 --- a/java/java-tests/testSrc/com/intellij/java/navigation/GotoActionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/navigation/GotoActionTest.groovy @@ -58,20 +58,20 @@ class GotoActionTest extends LightCodeInsightFixtureTestCase { assert [c, copy, cut, aardvark, eclaire, boom, deaf] == items.collect { it.valueText } } - static def matchedValue(String fork, String pattern) { + def matchedValue(String fork, String pattern) { matchedValue(fork, pattern, GotoActionModel.MatchMode.NAME) } - static def matchedValue(String fork, String pattern, GotoActionModel.MatchMode mode) { + def matchedValue(String fork, String pattern, GotoActionModel.MatchMode mode) { new GotoActionModel.MatchedValue(createAction(fork, mode), pattern) } - static def createAction(String text, GotoActionModel.MatchMode mode) { + def createAction(String text, GotoActionModel.MatchMode mode) { def action = new AnAction(text) { @Override void actionPerformed(AnActionEvent e) { } } - new GotoActionModel.ActionWrapper(action, "", mode, DataContext.EMPTY_CONTEXT) + new GotoActionModel.ActionWrapper(action, "", mode, DataContext.EMPTY_CONTEXT, new GotoActionModel(project, null, null, null)) } } diff --git a/java/java-tests/testSrc/com/intellij/java/navigation/GotoImplementationHandlerTest.java b/java/java-tests/testSrc/com/intellij/java/navigation/GotoImplementationHandlerTest.java index e2736c6edc99..0402c9c89dad 100644 --- a/java/java-tests/testSrc/com/intellij/java/navigation/GotoImplementationHandlerTest.java +++ b/java/java-tests/testSrc/com/intellij/java/navigation/GotoImplementationHandlerTest.java @@ -19,10 +19,7 @@ import com.intellij.JavaTestUtil; import com.intellij.codeInsight.navigation.GotoTargetHandler; import com.intellij.openapi.roots.ModuleRootModificationUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiMethod; +import com.intellij.psi.*; import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.fixtures.CodeInsightTestUtil; @@ -32,6 +29,8 @@ import com.intellij.util.containers.ContainerUtil; import java.util.Arrays; import java.util.List; +import static org.junit.Assert.assertNotEquals; + public class GotoImplementationHandlerTest extends JavaCodeInsightFixtureTestCase { public void testMultipleImplsFromAbstractCall() { PsiFile file = myFixture.addFileToProject("Foo.java", "public abstract class Hello {\n" + @@ -55,6 +54,29 @@ public class GotoImplementationHandlerTest extends JavaCodeInsightFixtureTestCas assertEquals(2, impls.length); } + public void testUnderInstanceOf() { + PsiFile file = myFixture.addFileToProject("Foo.java", "abstract class Hello {\n" + + " abstract void foo();\n" + + "\n" + + " void test(Hello h) {\n" + + " if(h instanceof Hello1) h.foo();\n" + + " }\n" + + " \n" + + " class Hello1 extends Hello {\n" + + " void foo() {}\n" + + " }\n" + + " class Hello2 extends Hello {\n" + + " void foo() {}\n" + + " }\n" + + "}"); + myFixture.configureFromExistingVirtualFile(file.getVirtualFile()); + + final PsiElement[] impls = getTargets(file); + assertEquals(1, impls.length); + assertTrue(impls[0] instanceof PsiMethod); + assertEquals("Hello.Hello1", ((PsiMethod)impls[0]).getContainingClass().getQualifiedName()); + } + public void testFromIncompleteCode() { PsiFile file = myFixture.addFileToProject("Foo.java", "public abstract class Hello {\n" + " abstract void foo();\n" + @@ -335,6 +357,17 @@ public class GotoImplementationHandlerTest extends JavaCodeInsightFixtureTestCas List names = ContainerUtil.map(targets, element -> ((PsiClass)element).getName()); + for(PsiElement element:targets) { + PsiClass psiClass = (PsiClass)element; + String name = psiClass.getName(); + if ("1".equals(name) || "2".equals(name)) { + assertEquals(null, psiClass.getModifierList()); + assertTrue(psiClass.hasModifierProperty(PsiModifier.FINAL)); + } else if (!"MyInterfaceImplementation".equals(name)) { + assertNotEquals(null, psiClass.getModifierList()); + } + } + assertContainsElements(names, "1"); assertContainsElements(names, "2"); assertContainsElements(names, "MyLocalClassImplementation"); diff --git a/java/java-tests/testSrc/com/intellij/java/parser/JavaParsingTestCase.java b/java/java-tests/testSrc/com/intellij/java/parser/JavaParsingTestCase.java index d3583be1d842..dc40b89c5af3 100644 --- a/java/java-tests/testSrc/com/intellij/java/parser/JavaParsingTestCase.java +++ b/java/java-tests/testSrc/com/intellij/java/parser/JavaParsingTestCase.java @@ -36,44 +36,39 @@ import com.intellij.psi.tree.IFileElementType; import com.intellij.psi.util.PsiUtil; import com.intellij.testFramework.LightVirtualFile; import com.intellij.testFramework.ParsingTestCase; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.io.IOException; +import java.util.function.Consumer; public abstract class JavaParsingTestCase extends ParsingTestCase { private LanguageLevel myLanguageLevel; - @SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"}) - public JavaParsingTestCase(@NonNls final String dataPath) { - super("psi/"+dataPath, "java", new JavaParserDefinition()); + public JavaParsingTestCase(String dataPath) { + super("psi/" + dataPath, "java", new JavaParserDefinition()); } @Override protected void setUp() throws Exception { super.setUp(); - myLanguageLevel = LanguageLevel.JDK_1_6; + myLanguageLevel = LanguageLevel.JDK_X; getProject().registerService(LanguageLevelProjectExtension.class, new LanguageLevelProjectExtensionImpl(getProject())); addExplicitExtension(LanguageASTFactory.INSTANCE, JavaLanguage.INSTANCE, new JavaASTFactory()); } @Override protected PsiFile createFile(String name, String text) { - final PsiFile file = super.createFile(name, text); + PsiFile file = super.createFile(name, text); file.putUserData(PsiUtil.FILE_LANGUAGE_LEVEL_KEY, myLanguageLevel); return file; } - protected interface TestParser { - void parse(PsiBuilder builder); - } - protected void setLanguageLevel(@NotNull LanguageLevel languageLevel) { myLanguageLevel = languageLevel; } - protected void doParserTest(final String text, final TestParser parser) { - final String name = getTestName(false); + protected void doParserTest(String text, Consumer parser) { + String name = getTestName(false); myFile = createPsiFile(name, text, parser); myFile.putUserData(PsiUtil.FILE_LANGUAGE_LEVEL_KEY, myLanguageLevel); try { @@ -85,9 +80,9 @@ public abstract class JavaParsingTestCase extends ParsingTestCase { } private static IFileElementType TEST_FILE_ELEMENT_TYPE = null; - private static TestParser TEST_PARSER; + private static Consumer TEST_PARSER; - private PsiFile createPsiFile(final String name, final String text, final TestParser parser) { + private PsiFile createPsiFile(String name, String text, Consumer parser) { if (TEST_FILE_ELEMENT_TYPE == null) { TEST_FILE_ELEMENT_TYPE = new MyIFileElementType(); } @@ -99,14 +94,14 @@ public abstract class JavaParsingTestCase extends ParsingTestCase { return new PsiJavaFileImpl(viewProvider) { @NotNull @Override - protected FileElement createFileElement(@NotNull final CharSequence text) { + protected FileElement createFileElement(@NotNull CharSequence text) { return new FileElement(TEST_FILE_ELEMENT_TYPE, text); } }; } - private static PsiBuilder createBuilder(final ASTNode chameleon) { - final PsiBuilder builder = JavaParserUtil.createBuilder(chameleon); + private static PsiBuilder createBuilder(ASTNode chameleon) { + PsiBuilder builder = JavaParserUtil.createBuilder(chameleon); builder.setDebugMode(true); return builder; } @@ -117,20 +112,20 @@ public abstract class JavaParsingTestCase extends ParsingTestCase { } @Override - public ASTNode parseContents(final ASTNode chameleon) { - final PsiBuilder builder = createBuilder(chameleon); + public ASTNode parseContents(ASTNode chameleon) { + PsiBuilder builder = createBuilder(chameleon); - final PsiBuilder.Marker root = builder.mark(); - TEST_PARSER.parse(builder); + PsiBuilder.Marker root = builder.mark(); + TEST_PARSER.accept(builder); if (!builder.eof()) { - final PsiBuilder.Marker unparsed = builder.mark(); + PsiBuilder.Marker unparsed = builder.mark(); while (!builder.eof()) builder.advanceLexer(); unparsed.error("Unparsed tokens"); } root.done(this); - final ASTNode rootNode = builder.getTreeBuilt(); + ASTNode rootNode = builder.getTreeBuilt(); return rootNode.getFirstChildNode(); } } -} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/parser/partial/StatementParserTest.java b/java/java-tests/testSrc/com/intellij/java/parser/partial/StatementParserTest.java index 417db865d800..4c9e40e6e86b 100644 --- a/java/java-tests/testSrc/com/intellij/java/parser/partial/StatementParserTest.java +++ b/java/java-tests/testSrc/com/intellij/java/parser/partial/StatementParserTest.java @@ -45,6 +45,9 @@ public class StatementParserTest extends JavaParsingTestCase { public void testLocalVar0() { doParserTest("List list;"); } public void testLocalVar1() { doParserTest("p.@A T

x;"); } + public void testLocalVar3() { doParserTest("var x;"); } + public void testLocalVar4() { doParserTest("final var x;"); } + public void testLocalVar5() { doParserTest("@A var x;"); } public void testDoNormal() { doParserTest("do{}while(true);"); } public void testDoIncomplete0() { doParserTest("do"); } @@ -58,6 +61,8 @@ public class StatementParserTest extends JavaParsingTestCase { public void testFor() { doParserTest("for(Iterator it = null; it.hasNext();) { String s = it.next(); }"); } public void testForNormal0() { doParserTest("for(int i = 0; i < 10; i++)\n ;"); } public void testForNormal1() { doParserTest("for( ; ; ) foo();"); } + public void testForNormal2() { doParserTest("for(var x = 0; ;) ;"); } + public void testForNormal3() { doParserTest("for(var x : list) ;"); } public void testForIncomplete0() { doParserTest("for"); } public void testForIncomplete1() { doParserTest("for("); } public void testForIncomplete2() { doParserTest("for(int i = 0;"); } @@ -68,6 +73,7 @@ public class StatementParserTest extends JavaParsingTestCase { public void testForIncomplete7() { doParserTest("for() foo();"); } public void testForIncomplete8() { doParserTest("for(int i = 0;) foo();"); } public void testForIncomplete9() { doParserTest("for(int i = 0; i < 0) foo();"); } + public void testForIncomplete10() { doParserTest("for(var x"); } public void testForInvalid0() { doParserTest("for(if (i<0) i++; ;) ;"); } public void testForInvalid1() { doParserTest("for(class C { }; ;) ;"); } @@ -128,6 +134,9 @@ public class StatementParserTest extends JavaParsingTestCase { public void testTryNormal8() { doParserTest("try(r;){}"); } public void testTryNormal9() { doParserTest("try(r1; R r2 = 0){}"); } public void testTryNormal10() { doParserTest("try(this){}"); } + public void testTryNormal11() { doParserTest("try(new R()){}"); } + public void testTryNormal12() { doParserTest("try(R.create()){}"); } + public void testTryNormal13() { doParserTest("try(var r = null){}"); } public void testTryIncomplete0() { doParserTest("try"); } public void testTryIncomplete1() { doParserTest("try{}"); } public void testTryIncomplete2() { doParserTest("try{}catch"); } @@ -147,8 +156,7 @@ public class StatementParserTest extends JavaParsingTestCase { public void testTryIncomplete16() { doParserTest("try(R r =){}"); } public void testTryIncomplete17() { doParserTest("try(R r = 0;;){}"); } public void testTryIncomplete18() { doParserTest("try(R r){}"); } - public void testTryNormal11() { doParserTest("try(new R()){}"); } - public void testTryNormal12() { doParserTest("try(R.create()){}"); } + public void testTryIncomplete19() { doParserTest("try(var r){}"); } public void testWhileNormal() { doParserTest("while (true) foo();"); } public void testWhileIncomplete0() { doParserTest("while"); } diff --git a/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaCompletionPolicy.java b/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaCompletionPolicy.java index 094b200bfd87..2ca548fef2f2 100644 --- a/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaCompletionPolicy.java +++ b/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaCompletionPolicy.java @@ -15,12 +15,14 @@ */ package com.intellij.java.propertyBased; +import com.intellij.lang.ASTNode; import com.intellij.lang.jvm.JvmModifier; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.testFramework.propertyBased.CompletionPolicy; +import com.siyeh.ig.psiutils.ExpressionUtils; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -56,7 +58,8 @@ class JavaCompletionPolicy extends CompletionPolicy { private static boolean isAdoptedOrphanPsiAfterClassEnd(PsiElement element) { PsiClass topmostClass = PsiTreeUtil.getTopmostParentOfType(element, PsiClass.class); if (topmostClass != null) { - PsiElement rBrace = topmostClass.getRBrace(); + ASTNode rBrace = topmostClass.getNode().findChildByType(JavaTokenType.RBRACE); + // not PsiClass#getRBrace, because we need the first one, and invalid classes can contain several '}' if (rBrace != null && rBrace.getTextRange().getStartOffset() < element.getTextRange().getStartOffset()) return true; } return false; @@ -77,6 +80,11 @@ class JavaCompletionPolicy extends CompletionPolicy { // https://youtrack.jetbrains.com/issue/IDEA-174744 on red code return false; } + if (PsiTreeUtil.getParentOfType(ref, PsiAnnotation.class) != null) { + if (target instanceof PsiMethod || target instanceof PsiField && !ExpressionUtils.isConstant((PsiField)target)) { + return false; // red code; + } + } if (isStaticWithInstanceQualifier(ref, target)) { return false; } diff --git a/java/java-tests/testSrc/com/intellij/java/psi/util/PropertyUtilTest.java b/java/java-tests/testSrc/com/intellij/java/psi/util/PropertyUtilTest.java index c5d55bbcc06d..a59dddaf36a2 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/util/PropertyUtilTest.java +++ b/java/java-tests/testSrc/com/intellij/java/psi/util/PropertyUtilTest.java @@ -17,56 +17,57 @@ package com.intellij.java.psi.util; import com.intellij.psi.*; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.testFramework.LightCodeInsightTestCase; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; public class PropertyUtilTest extends LightCodeInsightTestCase { public void testSuggestGetterName() { - assertEquals("isValid", PropertyUtil.suggestGetterName("valid", getType("boolean"))); - assertEquals("getValid", PropertyUtil.suggestGetterName("valid", getType("Object"))); - assertEquals("isValid", PropertyUtil.suggestGetterName(createField("valid", "boolean"))); - assertEquals("getValid", PropertyUtil.suggestGetterName(createField("valid", "Object"))); + assertEquals("isValid", PropertyUtilBase.suggestGetterName("valid", getType("boolean"))); + assertEquals("getValid", PropertyUtilBase.suggestGetterName("valid", getType("Object"))); + assertEquals("isValid", PropertyUtilBase.suggestGetterName(createField("valid", "boolean"))); + assertEquals("getValid", PropertyUtilBase.suggestGetterName(createField("valid", "Object"))); - assertEquals("getURL", PropertyUtil.suggestGetterName("URL", getType("Object"))); - assertEquals("getURL", PropertyUtil.suggestGetterName(createField("URL", "Object"))); + assertEquals("getURL", PropertyUtilBase.suggestGetterName("URL", getType("Object"))); + assertEquals("getURL", PropertyUtilBase.suggestGetterName(createField("URL", "Object"))); - assertEquals("isaURL", PropertyUtil.suggestGetterName(createField("aURL", "boolean"))); - assertEquals("getaURL", PropertyUtil.suggestGetterName(createField("aURL", "Object"))); - assertEquals("getBool", PropertyUtil.suggestGetterName(createField("bool", "java.lang.Boolean"))); + assertEquals("isaURL", PropertyUtilBase.suggestGetterName(createField("aURL", "boolean"))); + assertEquals("getaURL", PropertyUtilBase.suggestGetterName(createField("aURL", "Object"))); + assertEquals("getBool", PropertyUtilBase.suggestGetterName(createField("bool", "java.lang.Boolean"))); } public void testSuggestSetterName() { - assertEquals("setValid", PropertyUtil.suggestSetterName("valid")); - assertEquals("setValid", PropertyUtil.suggestSetterName(createField("valid", "Object"))); + assertEquals("setValid", PropertyUtilBase.suggestSetterName("valid")); + assertEquals("setValid", PropertyUtilBase.suggestSetterName(createField("valid", "Object"))); - assertEquals("setURL", PropertyUtil.suggestSetterName("URL")); - assertEquals("setURL", PropertyUtil.suggestSetterName(createField("URL", "Object"))); + assertEquals("setURL", PropertyUtilBase.suggestSetterName("URL")); + assertEquals("setURL", PropertyUtilBase.suggestSetterName(createField("URL", "Object"))); - assertEquals("setaURL", PropertyUtil.suggestSetterName("aURL")); - assertEquals("setaURL", PropertyUtil.suggestSetterName(createField("aURL", "Object"))); - assertEquals("setBool", PropertyUtil.suggestSetterName(createField("bool", "java.lang.Boolean"))); + assertEquals("setaURL", PropertyUtilBase.suggestSetterName("aURL")); + assertEquals("setaURL", PropertyUtilBase.suggestSetterName(createField("aURL", "Object"))); + assertEquals("setBool", PropertyUtilBase.suggestSetterName(createField("bool", "java.lang.Boolean"))); } public void testSuggestPropertyName() { - assertEquals("valid", PropertyUtil.getPropertyName("isValid")); - assertEquals("valid", PropertyUtil.getPropertyName("getValid")); - assertEquals("valid", PropertyUtil.getPropertyName("setValid")); + assertEquals("valid", PropertyUtilBase.getPropertyName("isValid")); + assertEquals("valid", PropertyUtilBase.getPropertyName("getValid")); + assertEquals("valid", PropertyUtilBase.getPropertyName("setValid")); - assertEquals("URL", PropertyUtil.getPropertyName("isURL")); - assertEquals("URL", PropertyUtil.getPropertyName("getURL")); - assertEquals("URL", PropertyUtil.getPropertyName("setURL")); + assertEquals("URL", PropertyUtilBase.getPropertyName("isURL")); + assertEquals("URL", PropertyUtilBase.getPropertyName("getURL")); + assertEquals("URL", PropertyUtilBase.getPropertyName("setURL")); - assertEquals("aURL", PropertyUtil.getPropertyName("isaURL")); - assertEquals("aURL", PropertyUtil.getPropertyName("getaURL")); - assertEquals("aURL", PropertyUtil.getPropertyName("setaURL")); + assertEquals("aURL", PropertyUtilBase.getPropertyName("isaURL")); + assertEquals("aURL", PropertyUtilBase.getPropertyName("getaURL")); + assertEquals("aURL", PropertyUtilBase.getPropertyName("setaURL")); } public void testBooleanPropertyGetters() { - assertTrue(PropertyUtil.hasGetterName(createMethod("isOk", "boolean"))); - assertFalse(PropertyUtil.hasGetterName(createMethod("isOk", CommonClassNames.JAVA_LANG_BOOLEAN))); - assertTrue(PropertyUtil.hasGetterName(createMethod("getOk", CommonClassNames.JAVA_LANG_BOOLEAN))); - assertFalse(PropertyUtil.hasGetterName(createMethod("isOk", "int"))); + assertTrue(PropertyUtilBase.hasGetterName(createMethod("isOk", "boolean"))); + assertFalse(PropertyUtilBase.hasGetterName(createMethod("isOk", CommonClassNames.JAVA_LANG_BOOLEAN))); + assertTrue(PropertyUtilBase.hasGetterName(createMethod("getOk", CommonClassNames.JAVA_LANG_BOOLEAN))); + assertFalse(PropertyUtilBase.hasGetterName(createMethod("isOk", "int"))); } private static PsiType getType(@NonNls String type) throws IncorrectOperationException { diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodTest.java index ab3261bfbedc..a33e72e7f3a3 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodTest.java @@ -679,6 +679,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doTest(); } + public void testTypeParamsListWithRecursiveDependencies() throws Exception { + doTest(); + } + public void testFromLambdaBody() throws Exception { doTest(); } diff --git a/java/openapi/src/com/intellij/refactoring/JavaRefactoringActionHandlerFactory.java b/java/openapi/src/com/intellij/refactoring/JavaRefactoringActionHandlerFactory.java index bd1da48b1504..be96b8126226 100644 --- a/java/openapi/src/com/intellij/refactoring/JavaRefactoringActionHandlerFactory.java +++ b/java/openapi/src/com/intellij/refactoring/JavaRefactoringActionHandlerFactory.java @@ -70,7 +70,7 @@ public abstract class JavaRefactoringActionHandlerFactory { * Creates handler for Introduce Parameter refactoring.

* * {@link RefactoringActionHandler#invoke(com.intellij.openapi.project.Project, com.intellij.psi.PsiElement[], com.intellij.openapi.actionSystem.DataContext)} - * accepts either 1 {@code PsiExpression}, that will be an initialzier for introduced parameter, + * accepts either 1 {@code PsiExpression}, that will be an initializer for introduced parameter, * or 1 {@code PsiLocalVariable}, that will be replaced with introduced parameter. */ public abstract RefactoringActionHandler createIntroduceParameterHandler(); @@ -171,7 +171,7 @@ public abstract class JavaRefactoringActionHandlerFactory { * Creates handler for Introduce Field refactoring.

* * {@link RefactoringActionHandler#invoke(com.intellij.openapi.project.Project, com.intellij.psi.PsiElement[], com.intellij.openapi.actionSystem.DataContext)} - * accepts either 1 {@code PsiExpression}, that will be an initialzier for introduced field, + * accepts either 1 {@code PsiExpression}, that will be an initializer for introduced field, * or 1 {@code PsiLocalVariable}, that will be replaced with introduced field. */ public abstract RefactoringActionHandler createIntroduceFieldHandler(); @@ -180,7 +180,7 @@ public abstract class JavaRefactoringActionHandlerFactory { * Creates handler for Introduce Variable refactoring.

* * {@link RefactoringActionHandler#invoke(com.intellij.openapi.project.Project, com.intellij.psi.PsiElement[], com.intellij.openapi.actionSystem.DataContext)} - * accepts 1 {@code PsiExpression}, that will be an initialzier for introduced variable. + * accepts 1 {@code PsiExpression}, that will be an initializer for introduced variable. */ public abstract RefactoringActionHandler createIntroduceVariableHandler(); @@ -188,7 +188,7 @@ public abstract class JavaRefactoringActionHandlerFactory { * Creates handler for Introduce Constant refactoring.

* * {@link RefactoringActionHandler#invoke(com.intellij.openapi.project.Project, com.intellij.psi.PsiElement[], com.intellij.openapi.actionSystem.DataContext)} - * accepts either 1 {@code PsiExpression}, that will be an initialzier for introduced constant, + * accepts either 1 {@code PsiExpression}, that will be an initializer for introduced constant, * or 1 {@code PsiLocalVariable}, that will be replaced with introduced constant. */ public abstract RefactoringActionHandler createIntroduceConstantHandler(); diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java index 346893a25869..7b821aecc8de 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java @@ -58,10 +58,10 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { } public void compile(PsiElement[] topLevelElements) { + final CompiledPattern pattern = myCompilingVisitor.getContext().getPattern(); for (PsiElement element : topLevelElements) { element.accept(this); - final MatchingHandler matchingHandler = myCompilingVisitor.getContext().getPattern().getHandler(element); - myCompilingVisitor.getContext().getPattern().setHandler(element, new TopLevelMatchingHandler(matchingHandler)); + pattern.setHandler(element, new TopLevelMatchingHandler(pattern.getHandler(element))); } } diff --git a/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java b/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java index a14473ef16cc..097467d2fc02 100644 --- a/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java +++ b/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java @@ -94,10 +94,10 @@ public class CompilerTestUtil { modulesToRestore.add(module); } } - table.removeJdk(internalJdk); for (Module module : modulesToRestore) { ModuleRootModificationUtil.setModuleSdk(module, internalJdk); } + table.removeJdk(internalJdk); BuildManager.getInstance().clearState(project); }); }); diff --git a/java/testFramework/src/com/intellij/testFramework/IdeaTestCase.java b/java/testFramework/src/com/intellij/testFramework/IdeaTestCase.java index f3aa67a29a0f..8e00e3d8d3f0 100644 --- a/java/testFramework/src/com/intellij/testFramework/IdeaTestCase.java +++ b/java/testFramework/src/com/intellij/testFramework/IdeaTestCase.java @@ -19,8 +19,6 @@ import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.LanguageLevelProjectExtension; -import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl; -import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.PsiClass; import com.intellij.psi.impl.JavaPsiFacadeEx; @@ -39,16 +37,12 @@ public abstract class IdeaTestCase extends PlatformTestCase { super.setUp(); LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_6); myJavaFacade = JavaPsiFacadeEx.getInstanceEx(myProject); - VirtualFilePointerManagerImpl filePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance(); - filePointerManager.storePointers(); } @Override protected void tearDown() throws Exception { myJavaFacade = null; super.tearDown(); - VirtualFilePointerManagerImpl filePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance(); - filePointerManager.assertPointersAreDisposed(); } public final JavaPsiFacadeEx getJavaFacade() { diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java index e640d861db36..24200700c39f 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java @@ -148,7 +148,6 @@ public class ConvertFieldToAtomicIntention extends PsiElementBaseIntentionAction else if (var instanceof PsiField) { ((PsiField)var).setInitializer(newInitializer); } - JavaCodeStyleManager.getInstance(var.getProject()).shortenClassReferences(var.getInitializer()); } modifierList.setModifierProperty(PsiModifier.FINAL, true); @@ -219,7 +218,7 @@ public class ConvertFieldToAtomicIntention extends PsiElementBaseIntentionAction @Override public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - return myContext.isValid(); + return getVariable(element) != null; } @Override diff --git a/java/typeMigration/testData/intentions/atomic/afterInLambdasAtWrite.java b/java/typeMigration/testData/intentions/atomic/afterInLambdasAtWrite.java new file mode 100644 index 000000000000..36775351cf01 --- /dev/null +++ b/java/typeMigration/testData/intentions/atomic/afterInLambdasAtWrite.java @@ -0,0 +1,21 @@ +// "Convert to atomic" "true" + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.*; + +public class InLambdas +{ + public void test() + { + AtomicInteger x = new AtomicInteger(); + // Also active at write point if it causes a compilation error + Runnable r1 = () -> x.getAndIncrement(); + Runnable r2 = () -> x.addAndGet(2); + Runnable r3 = () -> x.updateAndGet(v -> v * 2); + Runnable r4 = () -> x.set(5); + System.out.println(x.updateAndGet(v -> v / 3)); + IntSupplier s = () -> { + return x.updateAndGet(v -> v * 2); + }; + } +} \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/atomic/beforeInLambdasAtWrite.java b/java/typeMigration/testData/intentions/atomic/beforeInLambdasAtWrite.java new file mode 100644 index 000000000000..0a5ddd64b3c2 --- /dev/null +++ b/java/typeMigration/testData/intentions/atomic/beforeInLambdasAtWrite.java @@ -0,0 +1,20 @@ +// "Convert to atomic" "true" + +import java.util.function.*; + +public class InLambdas +{ + public void test() + { + int x = 0; + // Also active at write point if it causes a compilation error + Runnable r1 = () -> x++; + Runnable r2 = () -> x+=2; + Runnable r3 = () -> x*=2; + Runnable r4 = () -> x = 5; + System.out.println(x /= 3); + IntSupplier s = () -> { + return x *= 2; + }; + } +} \ No newline at end of file diff --git a/jetCheck/src/jetCheck/Generator.java b/jetCheck/src/jetCheck/Generator.java index faef09521431..05a01ee9b4d4 100644 --- a/jetCheck/src/jetCheck/Generator.java +++ b/jetCheck/src/jetCheck/Generator.java @@ -223,7 +223,7 @@ public class Generator { return from(data -> { long i1 = data.drawInt(); long i2 = data.drawInt(); - return Double.longBitsToDouble((i1 << 32) + i2); + return Double.longBitsToDouble((i1 << 32) + (i2 & 0xffffffffL)); }); } diff --git a/jetCheck/test/jetCheck/GeneratorTest.java b/jetCheck/test/jetCheck/GeneratorTest.java index e7f2f6300f12..35122b4d87d6 100644 --- a/jetCheck/test/jetCheck/GeneratorTest.java +++ b/jetCheck/test/jetCheck/GeneratorTest.java @@ -61,7 +61,7 @@ public class GeneratorTest extends PropertyCheckerTestCase { public void testSortedDoublesNonDescending() { PropertyFailure> failure = checkFalsified(listsOf(doubles()), l -> isSorted(l.stream().sorted().collect(Collectors.toList())), - 58); + 28); assertEquals(2, failure.getMinimalCounterexample().getExampleValue().size()); } diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/api/JavacNameTable.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/api/JavacNameTable.java index 9fda9fd6402e..0e07167e19bf 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/api/JavacNameTable.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/api/JavacNameTable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -51,13 +51,7 @@ public class JavacNameTable { @NotNull public String parseBinaryName(Element element) { - try { - return parseName(myElements.getBinaryName((TypeElement)element)); - } - catch (ClassCastException e) { - System.out.println(123); - throw e; - } + return parseName(myElements.getBinaryName((TypeElement)element)); } public boolean isAsterisk(Name name) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexUtil.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexUtil.java index d0c83802e223..b7c738f03c99 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexUtil.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package org.jetbrains.jps.backwardRefs; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Factory; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; @@ -28,6 +29,8 @@ import java.io.IOException; import java.util.*; public class BackwardReferenceIndexUtil { + private static final Logger LOG = Logger.getInstance(BackwardReferenceIndexUtil.class); + static void registerFile(String filePath, TObjectIntHashMap refs, List defs, @@ -50,6 +53,10 @@ public class BackwardReferenceIndexUtil { final LightRef.LightClassHierarchyElementDef aClass; if (sym.isAnonymous()) { final JavacRef[] classes = ((JavacDef.JavacClassDef)def).getSuperClasses(); + if (classes.length == 0) { + LOG.info("Seems that compilation will finish with errors in anonymous class inside file " + filePath); + continue; + } aClass = anonymousClassEnumerator.addAnonymous(sym.getName(), writer.asClassUsage(classes[0])); } else { aClass = writer.asClassUsage(sym); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java index 2ec75b4620d2..7fd974fd39b5 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java @@ -290,7 +290,9 @@ public class JarsBuilder { .appendToPath(relativeOutputPath, relativePath)); if (inputStream == null) { - addDirectoryEntry(jarOutputStream, pathInJar + "/", writtenPaths); + if (!pathInJar.endsWith("/")) { + addDirectoryEntry(jarOutputStream, pathInJar + "/", writtenPaths); + } } else if (writtenPaths.add(pathInJar)) { ZipEntry newEntry = new ZipEntry(pathInJar); diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java index eeae765574e3..753b6eb038cc 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java @@ -23,6 +23,8 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.testFramework.UsefulTestCase; import com.intellij.util.TimeoutUtil; import com.intellij.util.containers.hash.HashMap; +import com.intellij.util.io.DirectoryContentSpec; +import com.intellij.util.io.DirectoryContentSpecKt; import com.intellij.util.io.TestFileSystemBuilder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -116,12 +118,22 @@ public abstract class JpsBuildTestCase extends UsefulTestCase { expected.build().assertDirectoryEqual(new File(FileUtil.toSystemDependentName(outputPath))); } + protected static void assertOutput(final String outputPath, DirectoryContentSpec expected) { + DirectoryContentSpecKt.assertMatches(new File(outputPath), expected); + } + protected static void assertOutput(JpsModule module, TestFileSystemBuilder expected) { String outputUrl = JpsJavaExtensionService.getInstance().getOutputUrl(module, false); assertNotNull(outputUrl); assertOutput(JpsPathUtil.urlToPath(outputUrl), expected); } + protected static void assertOutput(JpsModule module, DirectoryContentSpec expected) { + String outputUrl = JpsJavaExtensionService.getInstance().getOutputUrl(module, false); + assertNotNull(outputUrl); + assertOutput(JpsPathUtil.urlToPath(outputUrl), expected); + } + protected static void change(String filePath) { change(filePath, null); } diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/rebuild/JpsRebuildTestCase.kt b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/rebuild/JpsRebuildTestCase.kt index 22982fbe5db1..1f7b0a3bef18 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/rebuild/JpsRebuildTestCase.kt +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/rebuild/JpsRebuildTestCase.kt @@ -18,7 +18,6 @@ package org.jetbrains.jps.builders.rebuild; import com.intellij.openapi.application.ex.PathManagerEx import com.intellij.openapi.util.io.FileUtil import com.intellij.util.io.DirectoryContentSpec -import com.intellij.util.io.assertMatches import org.jetbrains.jps.builders.CompileScopeTestBuilder import org.jetbrains.jps.builders.JpsBuildTestCase import org.jetbrains.jps.model.java.JpsJavaExtensionService @@ -48,10 +47,6 @@ abstract class JpsRebuildTestCase: JpsBuildTestCase() { assertOutput(myOutputDirectory.absolutePath, expectedOutput); } - fun assertOutput(targetFolder: String, expectedOutput: DirectoryContentSpec) { - File(targetFolder).assertMatches(expectedOutput) - } - fun loadAndRebuild(projectPath: String, pathVariables: Map) { loadProject(projectPath, pathVariables); rebuild(); diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTest.java b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTest.java deleted file mode 100644 index 71444e853556..000000000000 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTest.java +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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.jps.incremental.artifacts; - -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.util.PathUtil; -import org.jetbrains.jps.model.artifact.JpsArtifact; -import org.jetbrains.jps.model.java.JpsJavaExtensionService; -import org.jetbrains.jps.model.library.JpsLibrary; -import org.jetbrains.jps.model.module.JpsModule; -import org.jetbrains.jps.util.JpsPathUtil; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Enumeration; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.zip.CRC32; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; - -import static com.intellij.util.io.TestFileSystemBuilder.fs; -import static org.jetbrains.jps.incremental.artifacts.LayoutElementTestUtil.archive; -import static org.jetbrains.jps.incremental.artifacts.LayoutElementTestUtil.root; - -/** - * @author nik - */ -public class ArtifactBuilderTest extends ArtifactBuilderTestCase { - public void testFileCopy() { - final JpsArtifact a = addArtifact(root().fileCopy(createFile("file.txt", "foo"))); - buildAll(); - assertOutput(a, fs().file("file.txt", "foo")); - } - - public void testDir() { - final JpsArtifact a = addArtifact( - root() - .fileCopy(createFile("abc.txt")) - .dir("dir") - .fileCopy(createFile("xxx.txt", "bar")) - ); - buildAll(); - assertOutput(a, fs() - .file("abc.txt") - .dir("dir") - .file("xxx.txt", "bar") - ); - } - - public void testArchive() { - final JpsArtifact a = addArtifact( - root() - .archive("xxx.zip") - .fileCopy(createFile("X.class", "data")) - .dir("dir") - .fileCopy(createFile("Y.class")) - ); - buildAll(); - assertOutput(a, fs() - .archive("xxx.zip") - .file("X.class", "data") - .dir("dir") - .file("Y.class") - ); - } - - public void testTwoDirsInArchive() { - final String dir1 = PathUtil.getParentPath(PathUtil.getParentPath(createFile("dir1/a/x.txt"))); - final String dir2 = PathUtil.getParentPath(PathUtil.getParentPath(createFile("dir2/a/y.txt"))); - final JpsArtifact a = addArtifact( - root() - .archive("a.jar") - .dirCopy(dir1) - .dirCopy(dir2) - .dir("a").fileCopy(createFile("z.txt")) - ); - buildAll(); - assertOutput(a, fs() - .archive("a.jar") - .dir("a") - .file("x.txt") - .file("y.txt") - .file("z.txt") - ); - } - - public void testArchiveInArchive() { - final JpsArtifact a = addArtifact( - root() - .archive("a.jar") - .archive("b.jar") - .fileCopy(createFile("xxx.txt", "foo")) - ); - buildAll(); - assertOutput(a, fs() - .archive("a.jar") - .archive("b.jar") - .file("xxx.txt", "foo") - ); - } - - public void testIncludedArtifact() { - final JpsArtifact included = addArtifact("included", - root() - .fileCopy(createFile("aaa.txt"))); - final JpsArtifact a = addArtifact( - root() - .dir("dir") - .artifact(included) - .end() - .fileCopy(createFile("bbb.txt")) - ); - buildAll(); - - assertOutput(included, fs().file("aaa.txt")); - assertOutput(a, fs() - .dir("dir") - .file("aaa.txt") - .end() - .file("bbb.txt") - ); - } - - public void testMergeDirectories() { - final JpsArtifact included = addArtifact("included", - root().dir("dir").fileCopy(createFile("aaa.class"))); - final JpsArtifact a = addArtifact( - root() - .artifact(included) - .dir("dir") - .fileCopy(createFile("bbb.class"))); - buildAll(); - assertOutput(a, fs() - .dir("dir") - .file("aaa.class") - .file("bbb.class") - ); - } - - public void testCopyLibrary() { - final JpsLibrary library = addProjectLibrary("lib", getJUnitJarPath()); - final JpsArtifact a = addArtifact(root().lib(library)); - buildAll(); - assertOutput(a, fs().file("junit.jar")); - } - - public void testModuleOutput() { - final String file = createFile("src/A.java", "public class A {}"); - final JpsModule module = addModule("a", PathUtil.getParentPath(file)); - final JpsArtifact artifact = addArtifact(root().module(module)); - - buildArtifacts(artifact); - assertOutput(artifact, fs().file("A.class")); - } - - public void testCopyResourcesFromModuleOutput() { - String file = createFile("src/a.xml", ""); - JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(myProject).addResourcePattern("*.xml"); - JpsModule module = addModule("a", PathUtil.getParentPath(file)); - JpsArtifact artifact = addArtifact(root().module(module)); - buildArtifacts(artifact); - assertOutput(artifact, fs().file("a.xml")); - } - - public void testIgnoredFile() { - final String file = createFile("a/.svn/a.txt"); - createFile("a/svn/b.txt"); - final JpsArtifact a = addArtifact(root().parentDirCopy(PathUtil.getParentPath(file))); - buildAll(); - assertOutput(a, fs().dir("svn").file("b.txt")); - } - - public void testIgnoredFileInArchive() { - final String file = createFile("a/.svn/a.txt"); - createFile("a/svn/b.txt"); - final JpsArtifact a = addArtifact(archive("a.jar").parentDirCopy(PathUtil.getParentPath(file))); - buildAll(); - assertOutput(a, fs().archive("a.jar").dir("svn").file("b.txt")); - } - - public void testCopyExcludedFolder() { - //explicitly added excluded files should be copied (e.g. compile output) - final String file = createFile("xxx/excluded/a.txt"); - createFile("xxx/excluded/CVS"); - final String excluded = PathUtil.getParentPath(file); - final String dir = PathUtil.getParentPath(excluded); - - final JpsModule module = addModule("myModule"); - module.getContentRootsList().addUrl(JpsPathUtil.pathToUrl(dir)); - module.getExcludeRootsList().addUrl(JpsPathUtil.pathToUrl(excluded)); - - final JpsArtifact a = addArtifact(root().dirCopy(excluded)); - buildAll(); - assertOutput(a, fs().file("a.txt")); - } - - public void testCopyExcludedFile() { - //excluded files under non-excluded directory should not be copied - final String file = createFile("xxx/excluded/a.txt"); - createFile("xxx/b.txt"); - createFile("xxx/CVS"); - final String dir = PathUtil.getParentPath(PathUtil.getParentPath(file)); - - JpsModule module = addModule("myModule"); - module.getContentRootsList().addUrl(JpsPathUtil.pathToUrl(dir)); - module.getExcludeRootsList().addUrl(JpsPathUtil.pathToUrl(PathUtil.getParentPath(file))); - - final JpsArtifact a = addArtifact(root().dirCopy(dir)); - buildAll(); - assertOutput(a, fs().file("b.txt")); - } - - public void testExtractDirectory() { - final JpsArtifact a = addArtifact("a", root().dir("dir").extractedDir(getJUnitJarPath(), "/junit/textui/")); - buildAll(); - assertOutput(a, fs().dir("dir") - .file("ResultPrinter.class") - .file("TestRunner.class")); - } - - public void testExtractDirectoryFromExcludedJar() throws IOException { - String jarPath = createFile("dir/lib/j.jar"); - FileUtil.copy(new File(getJUnitJarPath()), new File(jarPath)); - JpsModule module = addModule("m"); - String libDir = PathUtil.getParentPath(jarPath); - module.getContentRootsList().addUrl(JpsPathUtil.pathToUrl(PathUtil.getParentPath(libDir))); - module.getExcludeRootsList().addUrl(JpsPathUtil.pathToUrl(libDir)); - final JpsArtifact a = addArtifact("a", root().extractedDir(jarPath, "/junit/textui/")); - buildAll(); - assertOutput(a, fs().file("ResultPrinter.class") - .file("TestRunner.class")); - } - - public void testPackExtractedDirectory() { - final JpsArtifact a = addArtifact("a", root().archive("a.jar").extractedDir(getJUnitJarPath(), "/junit/textui/")); - buildAll(); - assertOutput(a, fs().archive("a.jar") - .file("ResultPrinter.class") - .file("TestRunner.class")); - } - - public void testSelfIncludingArtifact() { - final JpsArtifact a = addArtifact("a", root()); - LayoutElementTestUtil.addArtifactToLayout(a, a); - assertBuildFailed(a); - } - - public void testCircularInclusion() { - final JpsArtifact a = addArtifact("a", root()); - final JpsArtifact b = addArtifact("b", root()); - LayoutElementTestUtil.addArtifactToLayout(a, b); - LayoutElementTestUtil.addArtifactToLayout(b, a); - assertBuildFailed(a); - assertBuildFailed(b); - } - - public void testArtifactContainingSelfIncludingArtifact() { - JpsArtifact c = addArtifact("c", root()); - final JpsArtifact a = addArtifact("a", root().artifact(c)); - LayoutElementTestUtil.addArtifactToLayout(a, a); - final JpsArtifact b = addArtifact("b", root().artifact(a)); - - buildArtifacts(c); - assertBuildFailed(b); - assertBuildFailed(a); - } - - public void testArtifactContainingSelfIncludingArtifactWithoutOutput() { - final JpsArtifact a = addArtifact("a", root()); - LayoutElementTestUtil.addArtifactToLayout(a, a); - final JpsArtifact b = addArtifact("b", root().artifact(a)); - a.setOutputPath(null); - - assertBuildFailed(b); - } - - //IDEA-73893 - public void testManifestFileIsFirstEntry() throws IOException { - final String firstFile = createFile("src/A.txt"); - final String manifestFile = createFile("src/MANIFEST.MF"); - final String lastFile = createFile("src/Z.txt"); - final JpsArtifact a = addArtifact(archive("a.jar").dir("META-INF") - .fileCopy(firstFile).fileCopy(manifestFile).fileCopy(lastFile)); - buildArtifacts(a); - final String jarPath = a.getOutputPath() + "/a.jar"; - JarFile jarFile = new JarFile(new File(jarPath)); - try { - final Enumeration entries = jarFile.entries(); - assertTrue(entries.hasMoreElements()); - final JarEntry firstEntry = entries.nextElement(); - assertEquals(JarFile.MANIFEST_NAME, firstEntry.getName()); - } - finally { - jarFile.close(); - } - } - - public void testPreserveCompressionMethodForEntryExtractedFromOneArchiveAndPackedIntoAnother() throws IOException { - String path = createFile("data/a.jar"); - ZipOutputStream output = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(new File(path)))); - try { - ZipEntry entry = new ZipEntry("a.txt"); - byte[] text = "text".getBytes(); - entry.setMethod(ZipEntry.STORED); - entry.setSize(text.length); - CRC32 crc32 = new CRC32(); - crc32.update(text); - entry.setCrc(crc32.getValue()); - output.putNextEntry(entry); - output.write(text); - output.closeEntry(); - } - catch (Exception e) { - e.printStackTrace(); - } - finally { - output.close(); - } - JpsArtifact a = addArtifact(archive("b.jar").extractedDir(path, "")); - buildAll(); - assertOutput(a, fs().archive("b.jar").file("a.txt", "text")); - - final String jarPath = a.getOutputPath() + "/b.jar"; - ZipFile zipFile = new ZipFile(new File(jarPath)); - try { - ZipEntry entry = zipFile.getEntry("a.txt"); - assertNotNull(entry); - assertEquals(ZipEntry.STORED, entry.getMethod()); - } - finally { - zipFile.close(); - } - } - - public void testBuildModuleBeforeArtifactIfSomeDirectoryInsideModuleOutputIsCopiedToArtifact() { - String src = PathUtil.getParentPath(PathUtil.getParentPath(createFile("src/x/A.java", "package x; class A{}"))); - JpsModule module = addModule("m", src); - File output = JpsJavaExtensionService.getInstance().getOutputDirectory(module, false); - JpsArtifact artifact = addArtifact(root().dirCopy(new File(output, "x").getAbsolutePath())); - rebuildAllModulesAndArtifacts(); - assertOutput(module, fs().dir("x").file("A.class")); - assertOutput(artifact, fs().file("A.class")); - } - - public void testClearOutputOnRebuild() { - String file = createFile("d/a.txt"); - JpsArtifact a = addArtifact(root().parentDirCopy(file)); - buildAll(); - createFileInArtifactOutput(a, "b.txt"); - buildAllAndAssertUpToDate(); - assertOutput(a, fs().file("a.txt").file("b.txt")); - - rebuildAllModulesAndArtifacts(); - assertOutput(a, fs().file("a.txt").file("b.txt")); - } - - public void testDeleteOnlyOutputFileOnRebuildForArchiveArtifact() { - String file = createFile("a.txt"); - JpsArtifact a = addArtifact(archive("a.jar").fileCopy(file)); - buildAll(); - createFileInArtifactOutput(a, "b.txt"); - buildAllAndAssertUpToDate(); - assertOutput(a, fs().archive("a.jar").file("a.txt").end().file("b.txt")); - - rebuildAllModulesAndArtifacts(); - assertOutput(a, fs().archive("a.jar").file("a.txt").end().file("b.txt")); - } - - public void testDoNotCreateEmptyArchive() { - String file = createFile("dir/a.txt"); - JpsArtifact a = addArtifact(archive("a.jar").parentDirCopy(file)); - delete(file); - buildAll(); - assertEmptyOutput(a); - } - - public void testDoNotCreateEmptyArchiveInsideArchive() { - String file = createFile("dir/a.txt"); - JpsArtifact a = addArtifact(archive("a.jar").archive("inner.jar").parentDirCopy(file)); - delete(file); - buildAll(); - assertEmptyOutput(a); - } - - public void testDoNotCreateEmptyArchiveFromExtractedDirectory() { - final JpsArtifact a = addArtifact("a", archive("a.jar").dir("dir").extractedDir(getJUnitJarPath(), "/xxx/")); - buildAll(); - assertEmptyOutput(a); - } - - public void testExtractNonExistentJarFile() { - JpsArtifact a = addArtifact(root().extractedDir("this-file-does-not-exist.jar", "/")); - buildAll(); - assertEmptyOutput(a); - } - - public void testRepackNonExistentJarFile() { - JpsArtifact a = addArtifact(archive("a.jar").extractedDir("this-file-does-not-exist.jar", "/").fileCopy(createFile("a.txt"))); - buildAll(); - assertOutput(a, fs().archive("a.jar").file("a.txt")); - } -} diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTest.kt b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTest.kt new file mode 100644 index 000000000000..39de1fc92c62 --- /dev/null +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTest.kt @@ -0,0 +1,461 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.jps.incremental.artifacts + +import com.intellij.openapi.util.io.FileUtil +import com.intellij.util.PathUtil +import com.intellij.util.io.directoryContent +import org.jetbrains.jps.incremental.artifacts.LayoutElementTestUtil.archive +import org.jetbrains.jps.incremental.artifacts.LayoutElementTestUtil.root +import org.jetbrains.jps.model.java.JpsJavaExtensionService +import org.jetbrains.jps.util.JpsPathUtil +import java.io.BufferedOutputStream +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.util.jar.JarFile +import java.util.zip.CRC32 +import java.util.zip.ZipEntry +import java.util.zip.ZipFile +import java.util.zip.ZipOutputStream + +/** + * @author nik + */ +class ArtifactBuilderTest : ArtifactBuilderTestCase() { + fun testFileCopy() { + val a = addArtifact(root().fileCopy(createFile("file.txt", "foo"))) + buildAll() + assertOutput(a, directoryContent { file("file.txt", "foo") }) + } + + fun testDir() { + val a = addArtifact( + root() + .fileCopy(createFile("abc.txt")) + .dir("dir") + .fileCopy(createFile("xxx.txt", "bar")) + ) + buildAll() + assertOutput(a, directoryContent { + file("abc.txt") + dir("dir") { + file("xxx.txt", "bar") + } + }) + } + + fun testArchive() { + val a = addArtifact( + root() + .archive("xxx.zip") + .fileCopy(createFile("X.class", "data")) + .dir("dir") + .fileCopy(createFile("Y.class")) + ) + buildAll() + assertOutput(a, directoryContent { + zip("xxx.zip") { + file("X.class", "data") + dir("dir") { + file("Y.class") + } + } + }) + } + + fun testTwoDirsInArchive() { + val dir1 = PathUtil.getParentPath(PathUtil.getParentPath(createFile("dir1/a/x.txt"))) + val dir2 = PathUtil.getParentPath(PathUtil.getParentPath(createFile("dir2/a/y.txt"))) + val a = addArtifact( + root() + .archive("a.jar") + .dirCopy(dir1) + .dirCopy(dir2) + .dir("a").fileCopy(createFile("z.txt")) + ) + buildAll() + assertOutput(a, directoryContent { + zip("a.jar") { + dir("a") { + file("x.txt") + file("y.txt") + file("z.txt") + } + } + }) + } + + fun testArchiveInArchive() { + val a = addArtifact( + root() + .archive("a.jar") + .archive("b.jar") + .fileCopy(createFile("xxx.txt", "foo")) + ) + buildAll() + assertOutput(a, directoryContent { + zip("a.jar") { + zip("b.jar") { + file("xxx.txt", "foo") + } + } + }) + } + + fun testIncludedArtifact() { + val included = addArtifact("included", + root() + .fileCopy(createFile("aaa.txt"))) + val a = addArtifact( + root() + .dir("dir") + .artifact(included) + .end() + .fileCopy(createFile("bbb.txt")) + ) + buildAll() + + assertOutput(included, directoryContent { file("aaa.txt") }) + assertOutput(a, directoryContent { + dir("dir") { + file("aaa.txt") + } + file("bbb.txt") + }) + } + + fun testMergeDirectories() { + val included = addArtifact("included", + root().dir("dir").fileCopy(createFile("aaa.class"))) + val a = addArtifact( + root() + .artifact(included) + .dir("dir") + .fileCopy(createFile("bbb.class"))) + buildAll() + assertOutput(a, directoryContent { + dir("dir") { + file("aaa.class") + file("bbb.class") + } + }) + } + + fun testCopyLibrary() { + val library = addProjectLibrary("lib", createFile("lib/a.jar")) + val a = addArtifact(root().lib(library)) + buildAll() + assertOutput(a, directoryContent { file("a.jar") }) + } + + fun testModuleOutput() { + val file = createFile("src/A.java", "public class A {}") + val module = addModule("a", PathUtil.getParentPath(file)) + val artifact = addArtifact(root().module(module)) + + buildArtifacts(artifact) + assertOutput(artifact, directoryContent { file("A.class") }) + } + + fun testCopyResourcesFromModuleOutput() { + val file = createFile("src/a.xml", "") + JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(myProject).addResourcePattern("*.xml") + val module = addModule("a", PathUtil.getParentPath(file)) + val artifact = addArtifact(root().module(module)) + buildArtifacts(artifact) + assertOutput(artifact, directoryContent { file("a.xml") }) + } + + fun testIgnoredFile() { + val file = createFile("a/.svn/a.txt") + createFile("a/svn/b.txt") + val a = addArtifact(root().parentDirCopy(PathUtil.getParentPath(file))) + buildAll() + assertOutput(a, directoryContent { dir("svn") { file("b.txt") }}) + } + + fun testIgnoredFileInArchive() { + val file = createFile("a/.svn/a.txt") + createFile("a/svn/b.txt") + val a = addArtifact(archive("a.jar").parentDirCopy(PathUtil.getParentPath(file))) + buildAll() + assertOutput(a, directoryContent { zip("a.jar") { dir("svn") { file("b.txt")}}}) + } + + fun testCopyExcludedFolder() { + //explicitly added excluded files should be copied (e.g. compile output) + val file = createFile("xxx/excluded/a.txt") + createFile("xxx/excluded/CVS") + val excluded = PathUtil.getParentPath(file) + val dir = PathUtil.getParentPath(excluded) + + val module = addModule("myModule") + module.contentRootsList.addUrl(JpsPathUtil.pathToUrl(dir)) + module.excludeRootsList.addUrl(JpsPathUtil.pathToUrl(excluded)) + + val a = addArtifact(root().dirCopy(excluded)) + buildAll() + assertOutput(a, directoryContent { file("a.txt") }) + } + + fun testCopyExcludedFile() { + //excluded files under non-excluded directory should not be copied + val file = createFile("xxx/excluded/a.txt") + createFile("xxx/b.txt") + createFile("xxx/CVS") + val dir = PathUtil.getParentPath(PathUtil.getParentPath(file)) + + val module = addModule("myModule") + module.contentRootsList.addUrl(JpsPathUtil.pathToUrl(dir)) + module.excludeRootsList.addUrl(JpsPathUtil.pathToUrl(PathUtil.getParentPath(file))) + + val a = addArtifact(root().dirCopy(dir)) + buildAll() + assertOutput(a, directoryContent { file("b.txt") }) + } + + fun testExtractDirectory() { + val jarFile = createXJarFile() + val a = addArtifact("a", root().dir("dir").extractedDir(jarFile, "/dir")) + buildAll() + assertOutput(a, directoryContent { + dir("dir") { + file("file.txt", "text") + } + }) + } + + @Throws(IOException::class) + fun testExtractDirectoryFromExcludedJar() { + val jarPath = createFile("dir/lib/j.jar") + val libDir = File(getOrCreateProjectDir(), "dir/lib") + directoryContent { + zip("j.jar") { + file("a.txt", "a") + } + }.generate(libDir) + val module = addModule("m") + val libDirPath = FileUtil.toSystemIndependentName(libDir.absolutePath) + module.contentRootsList.addUrl(JpsPathUtil.pathToUrl(PathUtil.getParentPath(libDirPath))) + module.excludeRootsList.addUrl(JpsPathUtil.pathToUrl(libDirPath)) + val a = addArtifact("a", root().extractedDir(jarPath, "")) + buildAll() + assertOutput(a, directoryContent { + file("a.txt", "a") + }) + } + + fun testPackExtractedDirectory() { + val zipPath = createXJarFile() + val a = addArtifact("a", root().archive("a.jar").extractedDir(zipPath, "/dir")) + buildAll() + assertOutput(a, directoryContent { zip("a.jar") { + file("file.txt", "text") + }}) + } + + fun `test no duplicated directory entries for extracted directory packed into JAR file`() { + val zipPath = createXJarFile() + val a = addArtifact("a", root().archive("a.jar").extractedDir(zipPath, "")) + buildAll() + ZipFile(File(a.outputPath, "a.jar")).use { + assertNotNull(it.getEntry("dir/")) + assertNull(it.getEntry("dir//")) + } + } + + private fun createXJarFile(): String { + val zipDir = directoryContent { + zip("x.jar") { + dir("dir") { + file("file.txt", "text") + } + } + }.generateInTempDir() + return FileUtil.toSystemIndependentName(File(zipDir, "x.jar").absolutePath) + } + + fun testSelfIncludingArtifact() { + val a = addArtifact("a", root()) + LayoutElementTestUtil.addArtifactToLayout(a, a) + assertBuildFailed(a) + } + + fun testCircularInclusion() { + val a = addArtifact("a", root()) + val b = addArtifact("b", root()) + LayoutElementTestUtil.addArtifactToLayout(a, b) + LayoutElementTestUtil.addArtifactToLayout(b, a) + assertBuildFailed(a) + assertBuildFailed(b) + } + + fun testArtifactContainingSelfIncludingArtifact() { + val c = addArtifact("c", root()) + val a = addArtifact("a", root().artifact(c)) + LayoutElementTestUtil.addArtifactToLayout(a, a) + val b = addArtifact("b", root().artifact(a)) + + buildArtifacts(c) + assertBuildFailed(b) + assertBuildFailed(a) + } + + fun testArtifactContainingSelfIncludingArtifactWithoutOutput() { + val a = addArtifact("a", root()) + LayoutElementTestUtil.addArtifactToLayout(a, a) + val b = addArtifact("b", root().artifact(a)) + a.outputPath = null + + assertBuildFailed(b) + } + + //IDEA-73893 + @Throws(IOException::class) + fun testManifestFileIsFirstEntry() { + val firstFile = createFile("src/A.txt") + val manifestFile = createFile("src/MANIFEST.MF") + val lastFile = createFile("src/Z.txt") + val a = addArtifact(archive("a.jar").dir("META-INF") + .fileCopy(firstFile).fileCopy(manifestFile).fileCopy(lastFile)) + buildArtifacts(a) + val jarPath = a.outputPath!! + "/a.jar" + val jarFile = JarFile(File(jarPath)) + jarFile.use { + val entries = it.entries() + assertTrue(entries.hasMoreElements()) + val firstEntry = entries.nextElement() + assertEquals(JarFile.MANIFEST_NAME, firstEntry.name) + } + } + + @Throws(IOException::class) + fun testPreserveCompressionMethodForEntryExtractedFromOneArchiveAndPackedIntoAnother() { + val path = createFile("data/a.jar") + val output = ZipOutputStream(BufferedOutputStream(FileOutputStream(File(path)))) + try { + val entry = ZipEntry("a.txt") + val text = "text".toByteArray() + entry.method = ZipEntry.STORED + entry.size = text.size.toLong() + val crc32 = CRC32() + crc32.update(text) + entry.crc = crc32.value + output.putNextEntry(entry) + output.write(text) + output.closeEntry() + } + catch (e: Exception) { + e.printStackTrace() + } + finally { + output.close() + } + val a = addArtifact(archive("b.jar").extractedDir(path, "")) + buildAll() + assertOutput(a, directoryContent { zip("b.jar") { file("a.txt", "text") }}) + + val jarPath = a.outputPath!! + "/b.jar" + val zipFile = ZipFile(File(jarPath)) + zipFile.use { + val entry = it.getEntry("a.txt") + assertNotNull(entry) + assertEquals(ZipEntry.STORED, entry.method) + } + } + + fun testBuildModuleBeforeArtifactIfSomeDirectoryInsideModuleOutputIsCopiedToArtifact() { + val src = PathUtil.getParentPath(PathUtil.getParentPath(createFile("src/x/A.java", "package x; class A{}"))) + val module = addModule("m", src) + val output = JpsJavaExtensionService.getInstance().getOutputDirectory(module, false) + val artifact = addArtifact(root().dirCopy(File(output, "x").absolutePath)) + rebuildAllModulesAndArtifacts() + assertOutput(module, directoryContent { dir("x") { file("A.class") }}) + assertOutput(artifact, directoryContent { file("A.class") }) + } + + fun testClearOutputOnRebuild() { + val file = createFile("d/a.txt") + val a = addArtifact(root().parentDirCopy(file)) + buildAll() + createFileInArtifactOutput(a, "b.txt") + buildAllAndAssertUpToDate() + assertOutput(a, directoryContent { + file("a.txt") + file("b.txt") + }) + + rebuildAllModulesAndArtifacts() + assertOutput(a, directoryContent { + file("a.txt") + file("b.txt") + }) + } + + fun testDeleteOnlyOutputFileOnRebuildForArchiveArtifact() { + val file = createFile("a.txt") + val a = addArtifact(archive("a.jar").fileCopy(file)) + buildAll() + createFileInArtifactOutput(a, "b.txt") + buildAllAndAssertUpToDate() + assertOutput(a, directoryContent { + zip("a.jar") { file("a.txt") } + file("b.txt") + }) + + rebuildAllModulesAndArtifacts() + assertOutput(a, directoryContent { + zip("a.jar") { file("a.txt") } + file("b.txt") + }) + } + + fun testDoNotCreateEmptyArchive() { + val file = createFile("dir/a.txt") + val a = addArtifact(archive("a.jar").parentDirCopy(file)) + delete(file) + buildAll() + assertEmptyOutput(a) + } + + fun testDoNotCreateEmptyArchiveInsideArchive() { + val file = createFile("dir/a.txt") + val a = addArtifact(archive("a.jar").archive("inner.jar").parentDirCopy(file)) + delete(file) + buildAll() + assertEmptyOutput(a) + } + + fun testDoNotCreateEmptyArchiveFromExtractedDirectory() { + val jarFile = createXJarFile() + val a = addArtifact("a", archive("a.jar").dir("dir").extractedDir(jarFile, "/xxx/")) + buildAll() + assertEmptyOutput(a) + } + + fun testExtractNonExistentJarFile() { + val a = addArtifact(root().extractedDir("this-file-does-not-exist.jar", "/")) + buildAll() + assertEmptyOutput(a) + } + + fun testRepackNonExistentJarFile() { + val a = addArtifact(archive("a.jar").extractedDir("this-file-does-not-exist.jar", "/").fileCopy(createFile("a.txt"))) + buildAll() + assertOutput(a, directoryContent { zip("a.jar") {file("a.txt")}}) + } +} diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java index ad9e8546b18a..3aa8ea50b5a3 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java @@ -18,6 +18,7 @@ package org.jetbrains.jps.incremental.artifacts; import com.intellij.openapi.util.io.FileUtil; import com.intellij.project.IntelliJProjectConfiguration; import com.intellij.util.ArrayUtil; +import com.intellij.util.io.DirectoryContentSpec; import com.intellij.util.io.TestFileSystemBuilder; import com.intellij.util.text.UniqueNameGenerator; import org.jetbrains.jps.builders.BuildResult; @@ -159,6 +160,10 @@ public abstract class ArtifactBuilderTestCase extends JpsBuildTestCase { assertOutput(a.getOutputPath(), expected); } + protected static void assertOutput(JpsArtifact a, DirectoryContentSpec expected) { + assertOutput(a.getOutputPath(), expected); + } + protected void buildAllAndAssertUpToDate() { buildAll(); assertUpToDate(); diff --git a/json/src/com/intellij/json/psi/impl/JSStringLiteralEscaper.java b/json/src/com/intellij/json/psi/impl/JSStringLiteralEscaper.java index 2bf9d03ee5f1..1f7b729012bd 100644 --- a/json/src/com/intellij/json/psi/impl/JSStringLiteralEscaper.java +++ b/json/src/com/intellij/json/psi/impl/JSStringLiteralEscaper.java @@ -13,6 +13,7 @@ public abstract class JSStringLiteralEscaper super(host); } + @Override public boolean decode(@NotNull final TextRange rangeInsideHost, @NotNull StringBuilder outChars) { String subText = rangeInsideHost.substring(myHost.getText()); @@ -24,12 +25,14 @@ public abstract class JSStringLiteralEscaper protected abstract boolean isRegExpLiteral(); + @Override public int getOffsetInHost(int offsetInDecoded, @NotNull final TextRange rangeInsideHost) { int result = offsetInDecoded < outSourceOffsets.length ? outSourceOffsets[offsetInDecoded] : -1; if (result == -1) return -1; return (result <= rangeInsideHost.getLength() ? result : rangeInsideHost.getLength()) + rangeInsideHost.getStartOffset(); } + @Override public boolean isOneLine() { return true; } diff --git a/license/eclipse_license2.txt b/license/eclipse_license2.txt new file mode 100644 index 000000000000..49ac72738101 --- /dev/null +++ b/license/eclipse_license2.txt @@ -0,0 +1,89 @@ +Eclipse Public License - v 2.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +“Contribution” means: + +a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and +b) in the case of each subsequent Contributor: +i) changes to the Program, and +ii) additions to the Program; +where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works. +“Contributor” means any person or entity that Distributes the Program. + +“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +“Program” means the Contributions Distributed in accordance with this Agreement. + +“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors. + +“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. + +“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. + +“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. + +“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. + +“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works. +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. +e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). +3. REQUIREMENTS + +3.1 If a Contributor Distributes the Program in any form, then: + +a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and +b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: +i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; +ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; +iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and +iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. +3.2 When the Program is Distributed as Source Code: + +a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and +b) a copy of this Agreement must be included with each copy of the Program. +3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. + +Exhibit A – Form of Secondary Licenses Notice + +“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.” + +Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses. + +If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. \ No newline at end of file diff --git a/native/WinElevator/README.txt b/native/WinElevator/README.txt index 76e810b6d5df..137a72c46080 100644 --- a/native/WinElevator/README.txt +++ b/native/WinElevator/README.txt @@ -18,7 +18,7 @@ Launcher then creates threads to read/write them to console. ------- How to build. You may open .sln from Visual Studio or use msbuild from VS command prompt: - msbuild Elevator.sln /p:Configuration=release + msbuild Elevator.sln /p:Configuration=release /property:Platform=x86 Building and signing on TC: @@ -41,3 +41,8 @@ Check you got "spam" in out.txt and "err" in "err.txt" Ensure permissions > launcher.exe python.exe -c "print(open('c:\\windows\\eggs.txt', 'w'))" Check no error + +-------- +How to check errors. +Both tools report errors as error codes, stderr and event log under "Application". +No event ids are registered, but you can check eventId and find appropriate ReportEvent call. \ No newline at end of file diff --git a/native/WinElevator/elevator/elevator.c b/native/WinElevator/elevator/elevator.c index 0fd99fd6d8e7..6fae3ce745ff 100644 --- a/native/WinElevator/elevator/elevator.c +++ b/native/WinElevator/elevator/elevator.c @@ -17,8 +17,22 @@ #include #include #include -#include -#include + + +#define ERR_INVALID_HANDLE -1 +#define ERR_CANT_INHERIT -2 +#define ERR_CANT_SET_CONSOLE -3 +#define ERR_BAD_COMMAND_LINE -4 +#define ERR_SET_DIR -5 +#define ERR_PARENT_ID -6 +#define ERR_GET_DESC -7 +#define ERR_BAD_DESC -8 +#define ERR_FAILED_TO_FIND -9 +#define ERR_FAILED_ATTACH - 10 +#define ERR_OPEN_PARENT - 11 +#define ERR_LAUNCHING - 12 +#define ERR_WAITING - 13 +#define ERR_PARENT_DIED -14 // UAC-enabled (in manifset) tool to launch ptocesses. @@ -31,7 +45,7 @@ // nDescriptor ELEV_DESC_* // nDescriptorFlags flags passed from launcher to check if descriptor should be connected // Returns 0 if ok, error otherwise. Could be windows error, EBADF or EMFILE for dup2 -static DWORD _ConnectIfNeededPipe(DWORD nParentPid, DWORD nDescriptor, FILE* stream, int nDescriptorFlags, _Out_ PHANDLE pRemoteProcessHandle) +static DWORD _ConnectIfNeededPipe(DWORD nParentPid, DWORD nDescriptor, FILE* stream, int nDescriptorFlags, _Out_ PHANDLE pRemoteProcessHandle, _In_ HANDLE eventSource) { if (!(nDescriptorFlags & nDescriptor)) { @@ -46,12 +60,14 @@ static DWORD _ConnectIfNeededPipe(DWORD nParentPid, DWORD nDescriptor, FILE* str HANDLE hPipe = CreateFile(sPipeName, access, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hPipe == INVALID_HANDLE_VALUE || hPipe == NULL) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_INVALID_HANDLE, NULL, 0, 0, NULL, NULL); return GetLastError(); } // Make inheritable by remote process if (!SetHandleInformation(hPipe, HANDLE_FLAG_INHERIT, TRUE)) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_CANT_INHERIT, NULL, 0, 0, NULL, NULL); return GetLastError(); } @@ -59,6 +75,7 @@ static DWORD _ConnectIfNeededPipe(DWORD nParentPid, DWORD nDescriptor, FILE* str DWORD hStdHandleToChange = ELEV_DESCR_GET_HANDLE(nDescriptor); if (!SetStdHandle(hStdHandleToChange, hPipe)) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_CANT_SET_CONSOLE, NULL, 0, 0, NULL, NULL); return GetLastError(); } @@ -73,36 +90,43 @@ static DWORD _ConnectIfNeededPipe(DWORD nParentPid, DWORD nDescriptor, FILE* str int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) { + HANDLE eventSource = RegisterEventSourceW(NULL, L"JB-Elevator"); + if (argc <= _ARG_DESCRIPTORS) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_BAD_COMMAND_LINE, NULL, 0, 0, NULL, NULL); fwprintf(stderr, L"Bad command line"); - return -1; + return ERR_BAD_COMMAND_LINE; } if (!SetCurrentDirectory(argv[_ARG_DIR])) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_SET_DIR, NULL, 0, 0, NULL, NULL); fwprintf(stderr, L"Failed to set directory to %s : %ld", argv[_ARG_DIR], GetLastError()); - return -1; + return ERR_SET_DIR; } DWORD nParentPid = _wtol(argv[_ARG_PID]); if (!nParentPid) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_PARENT_ID, NULL, 0, 0, NULL, NULL); fwprintf(stderr, L"Failed to get parent pid from %s", argv[_ARG_PID]); - return -1; + return ERR_PARENT_ID; } wchar_t* sDescriptorsStr = argv[_ARG_DESCRIPTORS]; size_t nDescriptorsLen = wcslen(sDescriptorsStr); if (!nDescriptorsLen) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_GET_DESC, NULL, 0, 0, NULL, NULL); fwprintf(stderr, L"Failed to get descriptors from %s", sDescriptorsStr); - return -1; + return ERR_GET_DESC; } - for(int i = 0; i < nDescriptorsLen; i++) + for(size_t i = 0; i < nDescriptorsLen; i++) { if (! iswdigit(sDescriptorsStr[i])) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_BAD_DESC, NULL, 0, 0, NULL, NULL); fwprintf(stderr, L"Bad descriptor %s", sDescriptorsStr); - return -1; + return ERR_BAD_DESC; } } int nDescriptorFlags = _wtoi(sDescriptorsStr); @@ -113,8 +137,9 @@ int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) wchar_t* sFromSeparator = wcsstr(GetCommandLine(), ELEV_COMMAND_LINE_SEPARATOR); if (! sFromSeparator) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_FAILED_TO_FIND, NULL, 0, 0, NULL, NULL); fwprintf(stderr, L"Failed to find %s in %s", ELEV_COMMAND_LINE_SEPARATOR, GetCommandLine()); - return -1; + return ERR_FAILED_TO_FIND; } // Add rest commandline WCHAR* sCommandLine = sFromSeparator + wcslen(ELEV_COMMAND_LINE_SEPARATOR); @@ -123,8 +148,9 @@ int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) FreeConsole(); if (!AttachConsole(nParentPid)) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_FAILED_ATTACH, NULL, 0, 0, NULL, NULL); fwprintf(stderr, L"Failed to attach console: %d", GetLastError()); - return 1; + return ERR_FAILED_ATTACH; } STARTUPINFO startupInfo; @@ -134,17 +160,17 @@ int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) DWORD nError; // No place to output errors yet. Event log is overkill here, so we use exit code. - nError = _ConnectIfNeededPipe(nParentPid, ELEV_DESCR_STDIN, stdin, nDescriptorFlags, &startupInfo.hStdInput); + nError = _ConnectIfNeededPipe(nParentPid, ELEV_DESCR_STDIN, stdin, nDescriptorFlags, &startupInfo.hStdInput, eventSource); if (nError != 0) { exit(nError); } - nError = _ConnectIfNeededPipe(nParentPid, ELEV_DESCR_STDOUT, stdout, nDescriptorFlags, &startupInfo.hStdOutput); + nError = _ConnectIfNeededPipe(nParentPid, ELEV_DESCR_STDOUT, stdout, nDescriptorFlags, &startupInfo.hStdOutput, eventSource); if (nError != 0) { exit(nError); } - nError = _ConnectIfNeededPipe(nParentPid, ELEV_DESCR_STDERR, stderr, nDescriptorFlags, &startupInfo.hStdError); + nError = _ConnectIfNeededPipe(nParentPid, ELEV_DESCR_STDERR, stderr, nDescriptorFlags, &startupInfo.hStdError, eventSource); if (nError != 0) { exit(nError); @@ -153,6 +179,7 @@ int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) HANDLE parentProcess = OpenProcess(SYNCHRONIZE, FALSE, nParentPid); if (!parentProcess) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_OPEN_PARENT, NULL, 0, 0, NULL, NULL); exit(GetLastError()); // If parent process can't be opened it probably dead } @@ -160,28 +187,31 @@ int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) if (!CreateProcess(NULL, sCommandLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &startupInfo, &processInfo)) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_LAUNCHING, NULL, 0, 0, NULL, NULL); fwprintf(stderr, L"Error launching process. Exit code %ld, command was %ls", GetLastError(), sCommandLine); - return 1; + return ERR_LAUNCHING; } HANDLE processesToWait[] = { parentProcess, processInfo.hProcess }; DWORD nWaitResult = WaitForMultipleObjects(2, processesToWait, FALSE, INFINITE); if (WAIT_FAILED == nWaitResult) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_WAITING, NULL, 0, 0, NULL, NULL); fwprintf(stderr, L"Error waiting processes: %ld", GetLastError()); - return -1; + return ERR_WAITING; } if (nWaitResult - WAIT_OBJECT_0 == 0) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_PARENT_DIED, NULL, 0, 0, NULL, NULL); fwprintf(stderr, L"Parent process (launcher) died?"); TerminateProcess(processInfo.hProcess, -1); - return -1; + return ERR_PARENT_DIED; } DWORD nExitCode = 0; GetExitCodeProcess(processInfo.hProcess, &nExitCode); - + DeregisterEventSource(eventSource); return nExitCode; } diff --git a/native/WinElevator/launcher/launcher.c b/native/WinElevator/launcher/launcher.c index 54247c0a794b..582e3e31f229 100644 --- a/native/WinElevator/launcher/launcher.c +++ b/native/WinElevator/launcher/launcher.c @@ -21,6 +21,14 @@ // Author: Ilya Kazakevich + +#define ERR_FAIL_READ -1 +#define ERR_FAIL_WRITE -2 +#define ERR_GET_DIR -3 +#define ERR_LAUNCH -4 +#define ERR_FAIL_WAIT -5 +#define ERR_CREATE_PIPE -6 + // Pipe that should be connected to remote process typedef struct { @@ -93,10 +101,14 @@ static void _AddStringToCommandLine(_Inout_ size_t* pchCurrentBufferChars, _Inou } } - // ThreadProc to connect pipe to remote process -static DWORD _CreateConnectPipe(_PIPE_CONNECTION_INFO* pPipeInfo) +static DWORD __stdcall _CreateConnectPipe(_PIPE_CONNECTION_INFO* pPipeInfo) { + WCHAR pipeName[40]; + wsprintf(pipeName, L"JB-Launcher-Pipe-%ld", pPipeInfo->nDescriptor); + HANDLE eventSource = RegisterEventSourceW(NULL, pipeName); + + ELEV_PIPE_NAME sPipeName; ELEV_GEN_PIPE_NAME(sPipeName, pPipeInfo->nRemoteProcessPid, pPipeInfo->nDescriptor); int access = (pPipeInfo->bFromExternalProcess ? PIPE_ACCESS_INBOUND : PIPE_ACCESS_OUTBOUND); @@ -111,14 +123,16 @@ static DWORD _CreateConnectPipe(_PIPE_CONNECTION_INFO* pPipeInfo) NULL); if (hExternalPipe == NULL || hExternalPipe == INVALID_HANDLE_VALUE) { - fwprintf(stderr, L"Failed to create in pipe: %ld", GetLastError()); - exit(-1); + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_CREATE_PIPE, NULL, 0, 0, NULL, NULL); + fwprintf(stderr, L"Failed to create in pipe: %ld", GetLastError()); + exit(ERR_CREATE_PIPE); } if (!ConnectNamedPipe(hExternalPipe, NULL)) { - fwprintf(stderr, L"Failed to wait for in pipe: %ld", GetLastError()); - exit(-1); + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_FAIL_WAIT, NULL, 0, 0, NULL, NULL); + fwprintf(stderr, L"Failed to wait for in pipe: %ld", GetLastError()); + exit(ERR_FAIL_WAIT); } @@ -139,8 +153,9 @@ static DWORD _CreateConnectPipe(_PIPE_CONNECTION_INFO* pPipeInfo) { break; } + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_FAIL_READ, NULL, 0, 0, NULL, NULL); fwprintf(stderr, L"Failed to read from %ld: %ld", pPipeInfo->nDescriptor, GetLastError()); - exit(-1); + exit(ERR_FAIL_READ); } if (!WriteFile(hToWrite, buffer, nBytesRead, &nBytesWritten, NULL)) { @@ -150,13 +165,17 @@ static DWORD _CreateConnectPipe(_PIPE_CONNECTION_INFO* pPipeInfo) { break; } + ReportEvent(eventSource, EVENTLOG_WARNING_TYPE, 0, ERR_FAIL_WRITE, NULL, 0, 0, NULL, NULL); fwprintf(stderr, L"Failed to write: %ld", GetLastError()); - exit(-1); + // Unability to write to remote pipe means there is nothing connected to stdout. + // Reason to report warning but not die (see IDEA-178958) + break; } FlushFileBuffers(hToWrite); } CloseHandle(hToWrite); CloseHandle(hToRead); + DeregisterEventSource(eventSource); return 0; } @@ -183,6 +202,7 @@ static void _LaunchPipeThread(_PIPE_CONNECTION_INFO* pPipeInfo, _Out_opt_ PHANDL int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) { + HANDLE eventSource = RegisterEventSourceW(NULL, L"JB-Launcher"); DWORD nExitCode = 0; @@ -197,7 +217,7 @@ int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) _CONFIGURE_PIPE_INFO(g_stdInPipe, ELEV_DESCR_STDIN, nPid, FALSE); - _mm_mfence(); // To make sure threads has access to g_ + MemoryBarrier(); // To make sure threads has access to g_ HANDLE arHandlesToWait[] = {NULL, NULL}; int nDescriptorFlags = 0; @@ -235,8 +255,9 @@ int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) WCHAR sPath[MAX_PATH + 1]; if(!GetModuleFileName(NULL, sPath, MAX_PATH)) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_GET_DIR, NULL, 0, 0, NULL, NULL); fprintf(stderr, "Failed to get directory: %ld", GetLastError()); - return 1; + return ERR_GET_DIR; } WCHAR sDrive[_MAX_DRIVE], sDir[_MAX_DIR], sFile[_MAX_FNAME], sExt[_MAX_EXT]; @@ -255,8 +276,9 @@ int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) if (!ShellExecuteEx(&execInfo)) { + ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_LAUNCH, NULL, 0, 0, NULL, NULL); fprintf(stderr, "Failed to launch process: %ld", GetLastError()); - return 1; + return ERR_LAUNCH; } // Wait for all threads @@ -271,5 +293,6 @@ int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) // Process should be ended here, lets wait WaitForSingleObject(execInfo.hProcess, INFINITE); GetExitCodeProcess(execInfo.hProcess, &nExitCode); + DeregisterEventSource(eventSource); return nExitCode; } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionElementsMergerBase.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionElementsMergerBase.java index b90128f9b96f..0494aa50d8f2 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionElementsMergerBase.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionElementsMergerBase.java @@ -20,7 +20,9 @@ import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.WriteExternalException; import org.jdom.Element; -import java.util.*; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; public abstract class InspectionElementsMergerBase extends InspectionElementsMerger { @@ -71,11 +73,12 @@ public abstract class InspectionElementsMergerBase extends InspectionElementsMer } protected Element merge(Map inspectionElements, boolean includeDefaults) { - LinkedHashMap scopes = null; - List content = null; + LinkedHashMap scopes = new LinkedHashMap<>(); boolean enabled = false; String level = null; + final Element toolElement = new Element(InspectionProfileImpl.INSPECTION_TOOL_TAG); + for (String sourceToolName : getSourceToolNames()) { Element sourceElement = inspectionElements.get(sourceToolName); @@ -95,12 +98,7 @@ public abstract class InspectionElementsMergerBase extends InspectionElementsMer } if (sourceElement != null) { - if (content == null) { - content = new ArrayList<>(); - scopes = new LinkedHashMap<>(); - } - - collectContent(sourceElement, content, scopes); + collectContent(sourceToolName, sourceElement, toolElement, scopes); enabled |= Boolean.parseBoolean(sourceElement.getAttributeValue(ToolsImpl.ENABLED_ATTRIBUTE)); if (level == null) { @@ -108,8 +106,7 @@ public abstract class InspectionElementsMergerBase extends InspectionElementsMer } } } - if (content != null && !content.isEmpty()) { - final Element toolElement = new Element(InspectionProfileImpl.INSPECTION_TOOL_TAG); + if (!toolElement.getChildren().isEmpty()) { toolElement.setAttribute(InspectionProfileImpl.CLASS_TAG, getMergedToolName()); toolElement.setAttribute(ToolsImpl.ENABLED_ATTRIBUTE, String.valueOf(enabled)); if (level != null) { @@ -120,9 +117,7 @@ public abstract class InspectionElementsMergerBase extends InspectionElementsMer for (Element scopeEl : scopes.values()) { toolElement.addContent(scopeEl); } - for (Element element : content) { - toolElement.addContent(element); - } + return toolElement; } return null; @@ -132,23 +127,37 @@ public abstract class InspectionElementsMergerBase extends InspectionElementsMer return element != null ? element.getAttributeValue(ToolsImpl.LEVEL_ATTRIBUTE) : HighlightSeverity.WARNING.getName(); } - protected static void collectContent(Element sourceElement, List options, Map scopes) { + protected void collectContent(String sourceToolName, Element sourceElement, Element toolElement, Map scopes) { if (sourceElement != null) { + Element wrapElement = wrapElement(sourceToolName, sourceElement, toolElement); for (Element element : sourceElement.getChildren()) { if ("scope".equals(element.getName())) { String scopeName = element.getAttributeValue("name"); if (scopes.containsKey(scopeName)) { - Element scopeElement = scopes.get(scopeName); - for (Element scopeEl : element.getChildren()) { - scopeElement.addContent(scopeEl.clone()); - } - } else { - scopes.put(scopeName, element.clone()); + copyScopeContent(sourceToolName, element, scopes.get(scopeName)); + } + else if (scopeName != null) { + Element scopeElement = element.clone(); + scopeElement.removeContent(); + scopes.put(scopeName, scopeElement); + copyScopeContent(sourceToolName, element, scopeElement); } - continue; } - options.add(element.clone()); + else { + wrapElement.addContent(element.clone()); + } } } } + + private void copyScopeContent(String sourceToolName, Element element, Element scopeElement) { + Element wrappedScope = wrapElement(sourceToolName, null, scopeElement); + for (Element scopeEl : element.getChildren()) { + wrappedScope.addContent(scopeEl.clone()); + } + } + + protected Element wrapElement(String sourceToolName, Element sourceElement, Element toolElement) { + return toolElement; + } } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/inspection-black-list.txt b/platform/analysis-impl/src/com/intellij/codeInspection/inspection-black-list.txt index 95c2c0cf8932..fff413e7c430 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/inspection-black-list.txt +++ b/platform/analysis-impl/src/com/intellij/codeInspection/inspection-black-list.txt @@ -140,8 +140,6 @@ com.siyeh.ig.j2me.OverlyLargePrimitiveArrayInitializerInspection com.siyeh.ig.javabeans.ClassWithoutNoArgConstructorInspection com.siyeh.ig.javadoc.UnnecessaryJavaDocLinkInspection com.siyeh.ig.jdk.AutoBoxingInspection -com.siyeh.ig.junit.JUnitAbstractTestClassNamingConventionInspection -com.siyeh.ig.junit.JUnitTestClassNamingConventionInspection com.siyeh.ig.junit.TestCaseWithNoTestMethodsInspection com.siyeh.ig.junit.TestMethodWithoutAssertionInspection com.siyeh.ig.logging.ClassWithMultipleLoggersInspection @@ -163,15 +161,11 @@ com.siyeh.ig.migration.ForCanBeForeachInspection com.siyeh.ig.migration.IfCanBeSwitchInspection com.siyeh.ig.modularization.ModuleWithTooFewClassesInspection com.siyeh.ig.modularization.ModuleWithTooManyClassesInspection -com.siyeh.ig.naming.AnnotationNamingConventionInspection com.siyeh.ig.naming.BooleanMethodNameMustStartWithQuestionInspection -com.siyeh.ig.naming.ClassNamingConventionInspection com.siyeh.ig.naming.ConstantNamingConventionInspection -com.siyeh.ig.naming.EnumeratedClassNamingConventionInspection com.siyeh.ig.naming.EnumeratedConstantNamingConventionInspection com.siyeh.ig.naming.InstanceMethodNamingConventionInspection com.siyeh.ig.naming.InstanceVariableNamingConventionInspection -com.siyeh.ig.naming.InterfaceNamingConventionInspection com.siyeh.ig.naming.LocalVariableNamingConventionInspection com.siyeh.ig.naming.NonBooleanMethodNameMayNotStartWithQuestionInspection com.siyeh.ig.naming.OverloadedMethodsWithSameNumberOfParametersInspection @@ -181,7 +175,6 @@ com.siyeh.ig.naming.ParameterNamingConventionInspection com.siyeh.ig.naming.QuestionableNameInspection com.siyeh.ig.naming.StaticMethodNamingConventionInspection com.siyeh.ig.naming.StaticVariableNamingConventionInspection -com.siyeh.ig.naming.TypeParameterNamingConventionInspection com.siyeh.ig.numeric.CastThatLosesPrecisionInspection com.siyeh.ig.numeric.ImplicitNumericConversionInspection com.siyeh.ig.numeric.IntegerMultiplicationImplicitCastToLongInspection diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ui/ConventionOptionsPanel.java b/platform/analysis-impl/src/com/intellij/codeInspection/ui/ConventionOptionsPanel.java index c4b5309f0a50..bf2886e6f2ab 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ui/ConventionOptionsPanel.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ui/ConventionOptionsPanel.java @@ -38,11 +38,18 @@ import java.util.regex.Pattern; public class ConventionOptionsPanel extends JPanel { private static final Logger LOG = Logger.getInstance(ConventionOptionsPanel.class); - + @Deprecated public ConventionOptionsPanel(@NotNull final InspectionProfileEntry owner, @NonNls final String minLengthProperty, @NonNls final String maxLengthProperty, @NonNls final String regexProperty, @NonNls final String regexPatternProperty, JComponent... extraOptions) { + this((Object)owner, minLengthProperty, maxLengthProperty, regexProperty, regexPatternProperty, extraOptions); + } + + public ConventionOptionsPanel(@NotNull final Object owner, + @NonNls final String minLengthProperty, @NonNls final String maxLengthProperty, + @NonNls final String regexProperty, @NonNls final String regexPatternProperty, + JComponent... extraOptions) { super(new GridBagLayout()); final JLabel patternLabel = new JLabel("Pattern:"); final JLabel minLengthLabel = new JLabel("Min length:"); @@ -149,19 +156,19 @@ public class ConventionOptionsPanel extends JPanel { add(new JPanel(), constraints); } - private static void setPropertyIntegerValue(InspectionProfileEntry owner, String property, Integer value) { + private static void setPropertyIntegerValue(Object owner, String property, Integer value) { setPropertyValue(owner, property, value); } - private static Integer getPropertyIntegerValue(InspectionProfileEntry owner, String property) { + private static Integer getPropertyIntegerValue(Object owner, String property) { return (Integer)getPropertyValue(owner, property); } - private static void setPropertyValue(@NotNull InspectionProfileEntry owner, String property, Object value) { + private static void setPropertyValue(@NotNull Object owner, String property, Object value) { ReflectionUtil.setField(owner.getClass(), owner, null, property, value); } - private static Object getPropertyValue(InspectionProfileEntry owner, String property) { + private static Object getPropertyValue(Object owner, String property) { return ReflectionUtil.getField(owner.getClass(), owner, null, property); } } diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/BuildMessages.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/BuildMessages.groovy index 326f901c38ff..6cd3bad7e4d9 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/BuildMessages.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/BuildMessages.groovy @@ -33,8 +33,13 @@ interface BuildMessages { void error(String message, Throwable cause) + /** + * @deprecated use {@link #compilationErrors(java.lang.String, java.util.List)} instead; if compilation errors are reported individually they are shown in separate blocks in TeamCity + */ void compilationError(String compilerName, String message) + void compilationErrors(String compilerName, List messages) + void progress(String message) def V block(String blockName, Closure body) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy index 44c8a9ec303c..8eba32f73f23 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy @@ -232,7 +232,7 @@ class CommunityLibraryLicenses { licenseUrl: "http://opensource.org/licenses/BSD-3-Clause"), new LibraryLicense(name: "JUnit", libraryName: "JUnit3", version: "3.8.1", license: "CPL 1.0", url: "http://junit.org/"), new LibraryLicense(name: "JUnit", libraryName: "JUnit4", version: "4.11", license: "CPL 1.0", url: "http://junit.org/"), - new LibraryLicense(name: "junit5_rt", libraryName: "junit5_rt", version: "5.0.0", license: "Eclipse Public License 1.0", + new LibraryLicense(name: "JUnit5", libraryName: "JUnit5", version: "5.0.0", license: "Eclipse Public License 2.0", url: "http://junit.org/"), new LibraryLicense(name: "jzlib", libraryName: "jzlib", version: "1.1.1", license: "BSD", url: "http://www.jcraft.com/jzlib/", licenseUrl: "http://www.jcraft.com/jzlib/LICENSE.txt"), @@ -289,8 +289,6 @@ class CommunityLibraryLicenses { licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0"), new LibraryLicense(name: "Objenesis", libraryName: "objenesis-1.2.jar", version: "1.2", license: "Apache 2.0", url: "http://objenesis.org/", licenseUrl: "http://apache.org/licenses/LICENSE-2.0"), - new LibraryLicense(name: "opentest4j", libraryName: "opentest4j", version: "1.0.0", license: "Apache 2.0", - url: "https://github.com/ota4j-team/opentest4j", licenseUrl: "http://apache.org/licenses/LICENSE-2.0"), new LibraryLicense(name: "pycodestyle.py", attachedTo: "python-helpers", version: "2.3.1", license: "MIT", url: "http://pycodestyle.readthedocs.io/"), new LibraryLicense(name: "PicoContainer", libraryName: "picocontainer", version: "1.2", license: "BSD", url: "https://github.com/codehaus/picocontainer", licenseUrl: "https://opensource.org/licenses/bsd-license.php"), diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy index 8d455a5f8a64..93894fee64b9 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy @@ -201,9 +201,7 @@ class CommunityRepositoryModules { mainJarName = "idea-junit.jar" withModule("junit_rt", "junit-rt.jar") withModule("junit5_rt", "junit5-rt.jar") - withProjectLibrary("junit5_rt") - withProjectLibrary("opentest4j") - withModuleLibrary("junit-jupiter-api-5.0.0.jar", "junit5_rt_tests", "") + withProjectLibrary("JUnit5") }, plugin("ByteCodeViewer") { mainJarName = "byteCodeViewer.jar" @@ -276,7 +274,6 @@ class CommunityRepositoryModules { withModule("instant-run-common", "sdk-tools.jar") withModule("instant-run-client", "sdk-tools.jar") withModule("instant-run-runtime", "sdk-tools.jar") - withModule("android-gradle-jps", "jps/android-gradle-jps.jar", false) withModule("android-jps-plugin", "jps/android-jps-plugin.jar", false) withProjectLibrary("freemarker-2.3.20") //todo[nik] move to module libraries withProjectLibrary("jgraphx-3.4.0.1") //todo[nik] move to module libraries diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CompilationErrorsLogMessage.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CompilationErrorsLogMessage.groovy new file mode 100644 index 000000000000..aabc3a9a4069 --- /dev/null +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CompilationErrorsLogMessage.groovy @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2017 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.intellij.build + +import groovy.transform.CompileStatic +/** + * @author nik + */ +@CompileStatic +class CompilationErrorsLogMessage extends LogMessage { + final String compilerName + final List errorMessages + + CompilationErrorsLogMessage(String compilerName, List errorMessages) { + super(Kind.COMPILATION_ERRORS, "$compilerName compilation errors") + this.errorMessages = errorMessages + this.compilerName = compilerName + } +} diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/LogMessage.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/LogMessage.groovy index 8c905d4abc53..acf7603932a4 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/LogMessage.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/LogMessage.groovy @@ -16,17 +16,19 @@ package org.jetbrains.intellij.build import groovy.transform.CompileStatic -import groovy.transform.Immutable - /** * @author nik */ @CompileStatic -@Immutable class LogMessage { enum Kind { - ERROR, WARNING, INFO, PROGRESS, BLOCK_STARTED, BLOCK_FINISHED, ARTIFACT_BUILT, COMPILATION_ERROR, STATISTICS + ERROR, WARNING, INFO, PROGRESS, BLOCK_STARTED, BLOCK_FINISHED, ARTIFACT_BUILT, @Deprecated COMPILATION_ERROR, COMPILATION_ERRORS, STATISTICS } final Kind kind final String text + + LogMessage(Kind kind, String text) { + this.kind = kind + this.text = text + } } \ No newline at end of file diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildMessagesImpl.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildMessagesImpl.groovy index 29913d3d9b9e..7a7c67dde7ce 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildMessagesImpl.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildMessagesImpl.groovy @@ -22,6 +22,7 @@ import org.apache.tools.ant.DefaultLogger import org.apache.tools.ant.Project import org.jetbrains.intellij.build.BuildMessageLogger import org.jetbrains.intellij.build.BuildMessages +import org.jetbrains.intellij.build.CompilationErrorsLogMessage import org.jetbrains.intellij.build.LogMessage import java.util.function.BiFunction @@ -95,7 +96,12 @@ class BuildMessagesImpl implements BuildMessages { @Override void compilationError(String compilerName, String message) { - processMessage(new LogMessage(LogMessage.Kind.COMPILATION_ERROR, "$compilerName:$message")) + compilationErrors(compilerName, [message]) + } + + @Override + void compilationErrors(String compilerName, List messages) { + processMessage(new CompilationErrorsLogMessage(compilerName, messages)) } @Override diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/ConsoleBuildMessageLogger.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/ConsoleBuildMessageLogger.groovy index 0a82d9877d86..edc9f711456a 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/ConsoleBuildMessageLogger.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/ConsoleBuildMessageLogger.groovy @@ -17,6 +17,7 @@ package org.jetbrains.intellij.build.impl import groovy.transform.CompileStatic import org.jetbrains.intellij.build.BuildMessageLogger +import org.jetbrains.intellij.build.CompilationErrorsLogMessage import org.jetbrains.intellij.build.LogMessage import java.util.function.BiFunction @@ -49,6 +50,10 @@ class ConsoleBuildMessageLogger extends BuildMessageLogger { case LogMessage.Kind.ARTIFACT_BUILT: printMessage("Artifact built: $message.text") break + case LogMessage.Kind.COMPILATION_ERRORS: + String errorsString = (message as CompilationErrorsLogMessage).errorMessages.join("\n") + printMessage("Compilation errors (${(message as CompilationErrorsLogMessage).compilerName}):\n$errorsString") + break default: printMessage(message.text) break diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/JpsCompilationRunner.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/JpsCompilationRunner.groovy index 5ee70eed4c62..41627addabdc 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/JpsCompilationRunner.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/JpsCompilationRunner.groovy @@ -34,6 +34,7 @@ import com.intellij.openapi.diagnostic.CompositeLogger import com.intellij.openapi.diagnostic.DefaultLogger import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.util.text.StringUtil +import com.intellij.util.containers.MultiMap import groovy.transform.CompileStatic import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NotNull @@ -146,7 +147,10 @@ class JpsCompilationRunner { context.messages.error("Compilation failed unexpectedly", e) } } - if (messageHandler.compilationFailed) { + if (!messageHandler.errorMessagesByCompiler.isEmpty()) { + for (Map.Entry> entry : messageHandler.errorMessagesByCompiler.entrySet()) { + context.messages.compilationErrors(entry.key, (List)entry.value) + } context.messages.error("Compilation failed") } else if (!compilationData.statisticsReported) { @@ -156,7 +160,7 @@ class JpsCompilationRunner { } private class AntMessageHandler implements MessageHandler { - private boolean compilationFailed + private MultiMap errorMessagesByCompiler = MultiMap.createLinked() private float progress = -1.0 @Override @@ -181,8 +185,7 @@ class JpsCompilationRunner { compilerName = "" messageText = text } - compilationFailed = true - context.messages.compilationError(compilerName, messageText) + errorMessagesByCompiler.putValue(compilerName, messageText) break case BuildMessage.Kind.WARNING: context.messages.warning(text) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TeamCityBuildMessageLogger.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TeamCityBuildMessageLogger.groovy index e7d72ae3c294..91ab76deb4fc 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TeamCityBuildMessageLogger.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TeamCityBuildMessageLogger.groovy @@ -18,6 +18,7 @@ package org.jetbrains.intellij.build.impl import groovy.transform.CompileStatic import org.apache.tools.ant.Project import org.jetbrains.intellij.build.BuildMessageLogger +import org.jetbrains.intellij.build.CompilationErrorsLogMessage import org.jetbrains.intellij.build.LogMessage import java.util.function.BiFunction @@ -77,6 +78,15 @@ class TeamCityBuildMessageLogger extends BuildMessageLogger { printTeamCityMessage("message", false, "text='$messageText' status='ERROR']"); printTeamCityMessage("compilationFinished", false, "compiler='$compiler']"); break + case LogMessage.Kind.COMPILATION_ERRORS: + String compiler = escape((message as CompilationErrorsLogMessage).compilerName) + printTeamCityMessage("compilationStarted", false, "compiler='$compiler']"); + (message as CompilationErrorsLogMessage).errorMessages.each { + String messageText = escape(it) + printTeamCityMessage("message", false, "text='$messageText' status='ERROR']"); + } + printTeamCityMessage("compilationFinished", false, "compiler='$compiler']"); + break } } diff --git a/platform/core-api/src/com/intellij/lexer/RestartableLexer.java b/platform/core-api/src/com/intellij/lexer/RestartableLexer.java new file mode 100644 index 000000000000..9aeaa369cd85 --- /dev/null +++ b/platform/core-api/src/com/intellij/lexer/RestartableLexer.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2017 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.lexer; + +public interface RestartableLexer { + /** + * Returns the start state of the lexer. + * + * @return the lexer state. + */ + int getStartState(); + + + /** + * Returns the restartable state of the lexer. + * + * @return the lexer state. + */ + int getRestartableState(); + +} diff --git a/platform/core-api/src/com/intellij/util/PathsList.java b/platform/core-api/src/com/intellij/util/PathsList.java index d5ca742f7e74..9bbcebcb9d2f 100644 --- a/platform/core-api/src/com/intellij/util/PathsList.java +++ b/platform/core-api/src/com/intellij/util/PathsList.java @@ -17,7 +17,6 @@ package com.intellij.util; import com.intellij.ide.highlighter.ArchiveFileType; import com.intellij.openapi.fileTypes.FileTypeRegistry; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.StandardFileSystems; @@ -122,14 +121,14 @@ public class PathsList { * @return {@link VirtualFile}s on local file system (returns jars as files). */ public List getVirtualFiles() { - return JBIterable.from(getPathList()).map(PATH_TO_LOCAL_VFILE).filter(Condition.NOT_NULL).toList(); + return JBIterable.from(getPathList()).filterMap(PATH_TO_LOCAL_VFILE).toList(); } /** * @return The same as {@link #getVirtualFiles()} but returns jars as {@code JarFileSystem} roots. */ public List getRootDirs() { - return JBIterable.from(getPathList()).map(PATH_TO_DIR).filter(Condition.NOT_NULL).toList(); + return JBIterable.from(getPathList()).filterMap(PATH_TO_DIR).toList(); } public void addAll(List allClasspath) { diff --git a/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java b/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java index 73aae5cbe260..bbc5558ac72a 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java @@ -23,6 +23,7 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -50,7 +51,6 @@ public class TransactionGuardImpl extends TransactionGuard { private TransactionIdImpl myCurrentTransaction; private boolean myWritingAllowed; private boolean myErrorReported; - private static boolean ourTestingTransactions; public TransactionGuardImpl() { myWriteSafeModalities.put(ModalityState.NON_MODAL, true); @@ -239,7 +239,9 @@ public class TransactionGuardImpl extends TransactionGuard { "Please ensure you're using invokeLater/invokeAndWait with a correct modality state (not \"any\"). " + "See TransactionGuard documentation for details." + "\n current modality=" + modality + - "\n known modalities=" + myWriteSafeModalities; + "\n known modalities:\n" + + StringUtil.join(myWriteSafeModalities.entrySet(), + entry -> String.format(" %s, writingAllowed=%s", entry.getKey(), entry.getValue()), ";\n"); } @Override @@ -252,9 +254,6 @@ public class TransactionGuardImpl extends TransactionGuard { private static boolean areAssertionsEnabled() { Application app = ApplicationManager.getApplication(); - if (app.isUnitTestMode() && !ourTestingTransactions) { - return false; - } if (app instanceof ApplicationEx && !((ApplicationEx)app).isLoaded()) { return false; } @@ -337,10 +336,6 @@ public class TransactionGuardImpl extends TransactionGuard { .toString(); } - public static void setTestingTransactions(boolean testingTransactions) { - ourTestingTransactions = testingTransactions; - } - private static class Transaction { @NotNull final Runnable runnable; @Nullable final TransactionIdImpl expectedContext; diff --git a/platform/core-impl/src/com/intellij/openapi/application/impl/ModalityStateEx.java b/platform/core-impl/src/com/intellij/openapi/application/impl/ModalityStateEx.java index 3a3a0b0ebee6..110126c100ca 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/impl/ModalityStateEx.java +++ b/platform/core-impl/src/com/intellij/openapi/application/impl/ModalityStateEx.java @@ -67,7 +67,9 @@ public class ModalityStateEx extends ModalityState { @NonNls public String toString() { - return this == NON_MODAL ? "ModalityState.NON_MODAL" : "ModalityState:" + StringUtil.join(getModalEntities(), ", "); + return this == NON_MODAL + ? "ModalityState.NON_MODAL" + : "ModalityState:{" + StringUtil.join(getModalEntities(), it -> "[" + it + "]", ", ") + "}"; } @Override diff --git a/platform/core-impl/src/com/intellij/openapi/progress/impl/CoreProgressManager.java b/platform/core-impl/src/com/intellij/openapi/progress/impl/CoreProgressManager.java index 4341e03e44ab..1479bb12418d 100644 --- a/platform/core-impl/src/com/intellij/openapi/progress/impl/CoreProgressManager.java +++ b/platform/core-impl/src/com/intellij/openapi/progress/impl/CoreProgressManager.java @@ -55,7 +55,7 @@ public class CoreProgressManager extends ProgressManager implements Disposable { final AtomicInteger myCurrentUnsafeProgressCount = new AtomicInteger(0); private final AtomicInteger myCurrentModalProgressCount = new AtomicInteger(0); - private static final boolean ENABLED = !"disabled".equals(System.getProperty("idea.ProcessCanceledException")); + public static final boolean ENABLED = !"disabled".equals(System.getProperty("idea.ProcessCanceledException")); private static CheckCanceledHook ourCheckCanceledHook; private ScheduledFuture myCheckCancelledFuture; // guarded by threadsUnderIndicator diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/PsiReferenceRegistrarImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/PsiReferenceRegistrarImpl.java index ed6ec1b23b00..9e069bdb9903 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/PsiReferenceRegistrarImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/PsiReferenceRegistrarImpl.java @@ -46,7 +46,16 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar { private final ConcurrentMap myBindingCache; private boolean myInitialized; + /** + * @deprecated To be removed in 2018.2 + */ + @Deprecated + @SuppressWarnings("unused") public PsiReferenceRegistrarImpl(final Language language) { + this(); + } + + PsiReferenceRegistrarImpl() { myBindingCache = ConcurrentFactoryMap.createMap(key-> { List result = ContainerUtil.newSmartList(); for (Class bindingClass : myBindingsMap.keySet()) { @@ -59,10 +68,6 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar { result.add(myNamedBindingsMap.get(bindingClass)); } } - if (language != Language.ANY) { - final PsiReferenceRegistrar anyRegistrar = ReferenceProvidersRegistry.getInstance().getRegistrar(Language.ANY); - Collections.addAll(result, ((PsiReferenceRegistrarImpl)anyRegistrar).myBindingCache.get(key)); - } //noinspection unchecked return result.toArray(new ProviderBinding[result.size()]); } diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistryImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistryImpl.java index 48c1d0ec650d..7157c416f24a 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistryImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistryImpl.java @@ -38,12 +38,12 @@ public class ReferenceProvidersRegistryImpl extends ReferenceProvidersRegistry { @NotNull private static PsiReferenceRegistrarImpl createRegistrar(Language language) { - PsiReferenceRegistrarImpl registrar = new PsiReferenceRegistrarImpl(language); - for (PsiReferenceContributor contributor : CONTRIBUTOR_EXTENSION.allForLanguage(language)) { + PsiReferenceRegistrarImpl registrar = new PsiReferenceRegistrarImpl(); + for (PsiReferenceContributor contributor : CONTRIBUTOR_EXTENSION.allForLanguageOrAny(language)) { contributor.registerReferenceProviders(registrar); } - List referenceProviderBeans = REFERENCE_PROVIDER_EXTENSION.allForLanguage(language); + List referenceProviderBeans = REFERENCE_PROVIDER_EXTENSION.allForLanguageOrAny(language); for (final PsiReferenceProviderBean providerBean : referenceProviderBeans) { final ElementPattern pattern = providerBean.createElementPattern(); if (pattern != null) { diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/util/LexerEditorHighlighter.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/util/LexerEditorHighlighter.java index 802c2e2ae397..849014ff8c0c 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/util/LexerEditorHighlighter.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/util/LexerEditorHighlighter.java @@ -17,6 +17,7 @@ package com.intellij.openapi.editor.ex.util; import com.intellij.lexer.FlexAdapter; import com.intellij.lexer.Lexer; +import com.intellij.lexer.RestartableLexer; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Attachment; import com.intellij.openapi.diagnostic.ExceptionWithAttachments; @@ -66,7 +67,7 @@ public class LexerEditorHighlighter implements EditorHighlighter, PrioritizedDoc myScheme = scheme; myLexer = highlighter.getHighlightingLexer(); myLexer.start(ArrayUtil.EMPTY_CHAR_SEQUENCE); - myInitialState = myLexer.getState(); + myInitialState = myLexer instanceof RestartableLexer ? ((RestartableLexer)myLexer).getRestartableState() : myLexer.getState(); myHighlighter = highlighter; mySegments = createSegments(); } @@ -375,7 +376,7 @@ public class LexerEditorHighlighter implements EditorHighlighter, PrioritizedDoc final TokenProcessor processor = createTokenProcessor(0); final int textLength = text.length(); - myLexer.start(text, 0, textLength, myInitialState); + myLexer.start(text, 0, textLength, myLexer instanceof RestartableLexer ? ((RestartableLexer)myLexer).getStartState() : myInitialState); mySegments.removeAll(); int i = 0; while (true) { diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/execution/ExternalSystemExecutionConsoleManager.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/execution/ExternalSystemExecutionConsoleManager.java index 67e6671b170e..b82be165e4b3 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/execution/ExternalSystemExecutionConsoleManager.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/execution/ExternalSystemExecutionConsoleManager.java @@ -28,6 +28,7 @@ import com.intellij.openapi.externalSystem.model.task.ExternalSystemTask; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author Vladislav.Soroka @@ -43,13 +44,23 @@ public interface ExternalSystemExecutionConsoleManager< @NotNull ProjectSystemId getExternalSystemId(); - @NotNull - ExternalSystemExecutionConsole attachExecutionConsole(@NotNull ExternalSystemTask task, - @NotNull Project project, - @NotNull ExternalSystemRunConfiguration configuration, - @NotNull Executor executor, - @NotNull ExecutionEnvironment env, - @NotNull ExternalSystemProcessHandler processHandler) throws ExecutionException; + /** + * @deprecated use {@link ExternalSystemExecutionConsoleManager#attachExecutionConsole(Project, ExternalSystemTask, ExecutionEnvironment, ProcessHandler)} + */ + @Nullable + default ExternalSystemExecutionConsole attachExecutionConsole(@NotNull ExternalSystemTask task, + @NotNull Project project, + @NotNull ExternalSystemRunConfiguration configuration, + @NotNull Executor executor, + @NotNull ExecutionEnvironment env, + @NotNull ExternalSystemProcessHandler processHandler) + throws ExecutionException {return null;} + + @Nullable + default ExternalSystemExecutionConsole attachExecutionConsole(@NotNull Project project, + @NotNull ExternalSystemTask task, + @Nullable ExecutionEnvironment env, + @Nullable ExternalSystemProcessHandler processHandler) {return null;} void onOutput(@NotNull ExternalSystemExecutionConsole executionConsole, @NotNull ExternalSystemProcessHandler processHandler, diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskNotificationListenerAdapter.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskNotificationListenerAdapter.java index ec9e20c8289a..276a2512b1b3 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskNotificationListenerAdapter.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskNotificationListenerAdapter.java @@ -1,6 +1,7 @@ package com.intellij.openapi.externalSystem.model.task; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author Denis Zhdanov @@ -8,51 +9,94 @@ import org.jetbrains.annotations.NotNull; */ public abstract class ExternalSystemTaskNotificationListenerAdapter implements ExternalSystemTaskNotificationListener { - @NotNull public static final ExternalSystemTaskNotificationListener NULL_OBJECT = new ExternalSystemTaskNotificationListenerAdapter() { }; + @NotNull public static final ExternalSystemTaskNotificationListener NULL_OBJECT = new ExternalSystemTaskNotificationListenerAdapter() { + }; + @Nullable + private final ExternalSystemTaskNotificationListener myDelegate; + + public ExternalSystemTaskNotificationListenerAdapter() { + this(null); + } + + public ExternalSystemTaskNotificationListenerAdapter(@Nullable ExternalSystemTaskNotificationListener delegate) { + myDelegate = delegate; + } /** * @deprecated use {@link #onStart(ExternalSystemTaskId, String)} */ public void onQueued(@NotNull ExternalSystemTaskId id, String workingDir) { + if (myDelegate != null) { + myDelegate.onQueued(id, workingDir); + } } @Override public void onStart(@NotNull ExternalSystemTaskId id, String workingDir) { - onQueued(id, workingDir); - onStart(id); + if (myDelegate != null) { + myDelegate.onStart(id, workingDir); + } + else { + onQueued(id, workingDir); + onStart(id); + } } /** * @deprecated use {@link #onStart(ExternalSystemTaskId, String)} */ public void onStart(@NotNull ExternalSystemTaskId id) { + if (myDelegate != null) { + myDelegate.onStart(id); + } } @Override public void onStatusChange(@NotNull ExternalSystemTaskNotificationEvent event) { + if (myDelegate != null) { + myDelegate.onStatusChange(event); + } } @Override public void onTaskOutput(@NotNull ExternalSystemTaskId id, @NotNull String text, boolean stdOut) { + if (myDelegate != null) { + myDelegate.onTaskOutput(id, text, stdOut); + } } @Override public void onEnd(@NotNull ExternalSystemTaskId id) { + if (myDelegate != null) { + myDelegate.onEnd(id); + } } @Override public void onSuccess(@NotNull ExternalSystemTaskId id) { + if (myDelegate != null) { + myDelegate.onSuccess(id); + } } @Override public void onFailure(@NotNull ExternalSystemTaskId id, @NotNull Exception e) { + if (myDelegate != null) { + myDelegate.onFailure(id, e); + } } @Override public void beforeCancel(@NotNull ExternalSystemTaskId id) { + if (myDelegate != null) { + myDelegate.beforeCancel(id); + } } @Override public void onCancel(@NotNull ExternalSystemTaskId id) { + if (myDelegate != null) { + myDelegate.onCancel(id); + } } } diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/manage/RunConfigHandlerExtension.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/manage/RunConfigHandlerExtension.java new file mode 100644 index 000000000000..68f5d9bef98d --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/manage/RunConfigHandlerExtension.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.service.project.manage; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +@ApiStatus.Experimental +public interface RunConfigHandlerExtension { + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.runConfigurationHandlerExtension"); + + default void process(@NotNull Project project, @NotNull String name, @NotNull Map cfg) {} + default void process(@NotNull Module module, @NotNull String name, @NotNull Map cfg) {} + default boolean canHandle(@NotNull String typeName) { + return false; + } +} \ No newline at end of file diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemSettings.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemSettings.java index 12c3da74b605..27074feb3f6b 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemSettings.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemSettings.java @@ -29,6 +29,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.stream.Collectors; /** * Common base class for external system settings. Defines a minimal api which is necessary for the common external system @@ -152,6 +153,9 @@ public abstract class AbstractExternalSystemSettings< } private void setLinkedProjectsSettings(@NotNull Collection settings, @Nullable ExternalSystemSettingsListener listener) { + // do not add invalid 'null' settings + settings = settings.stream().filter(ps -> ps.getExternalProjectPath() != null).collect(Collectors.toList()); + List added = ContainerUtilRt.newArrayList(); Map removed = ContainerUtilRt.newHashMap(myLinkedProjectsSettings); myLinkedProjectsSettings.clear(); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/DefaultExternalSystemExecutionConsoleManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/DefaultExternalSystemExecutionConsoleManager.java index 43580a35de87..ffdb0f83eafd 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/DefaultExternalSystemExecutionConsoleManager.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/DefaultExternalSystemExecutionConsoleManager.java @@ -29,6 +29,7 @@ import com.intellij.openapi.externalSystem.model.task.ExternalSystemTask; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author Vladislav.Soroka @@ -43,7 +44,18 @@ public class DefaultExternalSystemExecutionConsoleManager return ProjectSystemId.IDE; } - @NotNull + @Nullable + @Override + public ExecutionConsole attachExecutionConsole(@NotNull Project project, + @NotNull ExternalSystemTask task, + @Nullable ExecutionEnvironment env, + @Nullable ProcessHandler processHandler) { + ConsoleView executionConsole = TextConsoleBuilderFactory.getInstance().createBuilder(project).getConsole(); + executionConsole.attachToProcess(processHandler); + return executionConsole; + } + + @Nullable @Override public ExecutionConsole attachExecutionConsole(@NotNull ExternalSystemTask task, @NotNull Project project, @@ -51,9 +63,7 @@ public class DefaultExternalSystemExecutionConsoleManager @NotNull Executor executor, @NotNull ExecutionEnvironment env, @NotNull ProcessHandler processHandler) throws ExecutionException { - ConsoleView executionConsole = TextConsoleBuilderFactory.getInstance().createBuilder(project).getConsole(); - executionConsole.attachToProcess(processHandler); - return executionConsole; + return attachExecutionConsole(project, task, env, processHandler); } @Override diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java index 197a2239f559..43651b2b724e 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java @@ -15,9 +15,7 @@ */ package com.intellij.openapi.externalSystem.service.execution; -import com.intellij.build.BuildProgressListener; -import com.intellij.build.BuildViewManager; -import com.intellij.build.TasksViewManager; +import com.intellij.build.*; import com.intellij.build.events.BuildEvent; import com.intellij.build.events.impl.FailureResultImpl; import com.intellij.build.events.impl.FinishBuildEventImpl; @@ -52,7 +50,10 @@ import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.execution.ExternalSystemExecutionConsoleManager; import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; -import com.intellij.openapi.externalSystem.model.task.*; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationEvent; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListenerAdapter; import com.intellij.openapi.externalSystem.model.task.event.ExternalSystemTaskExecutionEvent; import com.intellij.openapi.externalSystem.service.internal.ExternalSystemExecuteTaskTask; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; @@ -67,6 +68,7 @@ import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.ToolWindowId; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.ArrayUtil; import com.intellij.util.ExceptionUtil; @@ -87,6 +89,7 @@ import java.io.IOException; import java.io.InputStream; import static com.intellij.openapi.externalSystem.util.ExternalSystemUtil.convert; +import static com.intellij.openapi.externalSystem.util.ExternalSystemUtil.getConsoleManagerFor; /** * @author Denis Zhdanov @@ -283,18 +286,26 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i consoleManager = getConsoleManagerFor(task); final ExecutionConsole consoleView = - consoleManager.attachExecutionConsole(task, myProject, myConfiguration, executor, myEnv, processHandler); - AnAction[] restartActions = consoleManager.getRestartActions(consoleView); - - Disposer.register(myProject, consoleView); + consoleManager.attachExecutionConsole(myProject, task, myEnv, processHandler); + AnAction[] restartActions; + if (consoleView == null) { + restartActions = AnAction.EMPTY_ARRAY; + } + else { + Disposer.register(myProject, consoleView); + restartActions = consoleManager.getRestartActions(consoleView); + } Class progressListenerClazz = task.getUserData(PROGRESS_LISTENER_KEY); final BuildProgressListener progressListener = progressListenerClazz != null ? ServiceManager.getService(myProject, progressListenerClazz) - : ServiceManager.getService(myProject, TasksViewManager.class); + : myDebugPort > 0 + ? ServiceManager.getService(myProject, DebugTasksViewManager.class) + : ServiceManager.getService(myProject, RunTasksViewManager.class); final String executionName = StringUtil.isNotEmpty(mySettings.getExecutionName()) ? mySettings.getExecutionName() - : AbstractExternalSystemTaskConfigurationType.generateName( + : StringUtil.isNotEmpty(myConfiguration.getName()) + ? myConfiguration.getName() : AbstractExternalSystemTaskConfigurationType.generateName( myProject, mySettings.getExternalSystemId(), mySettings.getExternalProjectPath(), mySettings.getTaskNames(), mySettings.getExecutionName(), ": ", ""); @@ -321,7 +332,7 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i long eventTime = System.currentTimeMillis(); AnAction rerunTaskAction = new MyTaskRerunAction(progressListener, myEnv, myContentDescriptor); progressListener.onEvent( - new StartBuildEventImpl(id, executionName, eventTime, "running...") + new StartBuildEventImpl(new DefaultBuildDescriptor(id, executionName, workingDir, eventTime), "running...") .withProcessHandler(processHandler, view -> { processHandler.notifyTextAvailable(greeting + "\n\n", ProcessOutputTypes.SYSTEM); foldGreetingOrFarewell(consoleView, greeting, true); @@ -329,7 +340,8 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i .withContentDescriptorSupplier(() -> myContentDescriptor) .withRestartAction(rerunTaskAction) .withRestartActions(restartActions) - .withExecutionEnvironment(myEnv)); + .withExecutionEnvironment(myEnv) + ); } } @@ -394,20 +406,15 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i public void setContentDescriptor(@Nullable RunContentDescriptor contentDescriptor) { myContentDescriptor = contentDescriptor; - } - } - - @NotNull - private static ExternalSystemExecutionConsoleManager - getConsoleManagerFor(@NotNull ExternalSystemTask task) { - for (ExternalSystemExecutionConsoleManager executionConsoleManager : ExternalSystemExecutionConsoleManager.EP_NAME.getExtensions()) { - if (executionConsoleManager.isApplicableFor(task)) { - //noinspection unchecked - return executionConsoleManager; + if (contentDescriptor != null) { + contentDescriptor.setExecutionId(myEnv.getExecutionId()); + contentDescriptor.setContentToolWindowId(ToolWindowId.BUILD); + RunnerAndConfigurationSettings settings = myEnv.getRunnerAndConfigurationSettings(); + if (settings != null) { + contentDescriptor.setActivateToolWindowWhenAdded(settings.isActivateToolWindowBeforeRun()); + } } } - - return new DefaultExternalSystemExecutionConsoleManager(); } private static void foldGreetingOrFarewell(ExecutionConsole consoleView, String text, boolean isGreeting) { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskDebugRunner.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskDebugRunner.java index 40eccd79abc5..14396d001113 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskDebugRunner.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskDebugRunner.java @@ -60,7 +60,7 @@ public class ExternalSystemTaskDebugRunner extends GenericDebuggerRunner { RunContentDescriptor descriptor = new RunContentDescriptor(runContentDescriptor.getExecutionConsole(), runContentDescriptor.getProcessHandler(), runContentDescriptor.getComponent(), runContentDescriptor.getDisplayName(), - runContentDescriptor.getIcon(), runContentDescriptor.getActivationCallback(), + runContentDescriptor.getIcon(), null, runContentDescriptor.getRestartActions()) { @Override public boolean isHiddenContent() { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskRunner.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskRunner.kt index 9abeff94bfe5..ec1ced4711df 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskRunner.kt +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskRunner.kt @@ -50,7 +50,7 @@ class ExternalSystemTaskRunner : GenericProgramRunner() { state.setContentDescriptor(runContentDescriptor) val descriptor = object : RunContentDescriptor(runContentDescriptor.executionConsole, runContentDescriptor.processHandler, runContentDescriptor.component, runContentDescriptor.displayName, - runContentDescriptor.icon, runContentDescriptor.activationCallback, + runContentDescriptor.icon, null, runContentDescriptor.restartActions) { override fun isHiddenContent(): Boolean = true } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/RunConfigurationHandler.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/RunConfigurationHandler.kt index 7e29f35fd131..f35eb484edea 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/RunConfigurationHandler.kt +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/RunConfigurationHandler.kt @@ -19,13 +19,12 @@ import com.intellij.execution.RunManager import com.intellij.execution.application.ApplicationConfiguration import com.intellij.execution.application.ApplicationConfigurationType import com.intellij.execution.configurations.ConfigurationTypeUtil -import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.externalSystem.model.project.ConfigurationData import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project -import org.jetbrains.annotations.ApiStatus /** * Created by Nikita.Skvortsov @@ -34,49 +33,54 @@ import org.jetbrains.annotations.ApiStatus class RunConfigurationHandler: ConfigurationHandler { + companion object { + val LOG = Logger.getInstance(RunConfigurationHandler::class.java) + } + override fun apply(module: Module, modelsProvider: IdeModifiableModelsProvider, configuration: ConfigurationData) { - val runCfgMap = configuration.find("runConfigurations") - - if (runCfgMap !is Map<*,*>) return - - runCfgMap.forEach { name, cfg -> - if (name !is String) return@forEach // TODO logs - if (cfg !is Map<*, *>) return@forEach - if (cfg["type"] == null) return@forEach - - val runCfgType = cfg["type"] as? String ?: return@forEach - RunConfigHandlerExtensionManager.handlerForType(runCfgType)?.process(module, name, cfg as Map) + configuration.eachRunConfiguration { typeName, name, cfg -> + RunConfigHandlerExtensionManager.handlerForType(typeName)?.process(module, name, cfg ) } } override fun apply(project: Project, modelsProvider: IdeModifiableModelsProvider, configuration: ConfigurationData) { - val runCfgMap = configuration.find("runConfigurations") + configuration.eachRunConfiguration { typeName, name, cfg -> + RunConfigHandlerExtensionManager.handlerForType(typeName)?.process(project, name, cfg) + } + } + + private fun ConfigurationData.eachRunConfiguration(f: (String, String, Map) -> Unit) { + val runCfgMap = find("runConfigurations") if (runCfgMap !is Map<*,*>) return runCfgMap.forEach { name, cfg -> - if (name !is String) return@forEach // TODO logs - if (cfg !is Map<*,*>) return@forEach - if (cfg["type"] == null) return@forEach + if (name !is String) { + RunConfigurationHandler.LOG.warn("unexpected key type in runConfigurations map: ${name?.javaClass?.name}, skipping") + return@forEach + } + if (cfg !is Map<*, *>) { + RunConfigurationHandler.LOG.warn("unexpected value type in runConfigurations map: ${cfg?.javaClass?.name}, skipping") + return@forEach + } - val runCfgType = cfg["type"] as? String ?: return@forEach - RunConfigHandlerExtensionManager.handlerForType(runCfgType)?.process(project, name, cfg as Map) + val typeName = cfg["type"] as? String + + if (typeName == null) { + RunConfigurationHandler.LOG.warn("Missing type for run configuration: ${name}, skipping") + return@forEach + } + + try { + f(typeName, name, cfg as Map) + } catch (e: Exception) { + RunConfigurationHandler.LOG.warn("Error occurred when importing run configuration ${name}: ${e.message}", e) + } } } } -@ApiStatus.Experimental -interface RunConfigHandlerExtension { - companion object { - val EP_NAME = ExtensionPointName.create("com.intellij.runConfigurationHandlerExtension") - } - - fun process(project: Project, name: String, cfg: Map) {} - fun process(module: Module, name: String, cfg: Map) {} - fun canHandle(typeName: String): Boolean = false -} - class RunConfigHandlerExtensionManager { companion object { fun handlerForType(typeName: String): RunConfigHandlerExtension? = @@ -85,21 +89,21 @@ class RunConfigHandlerExtensionManager { } class ApplicationRunConfigHandler: RunConfigHandlerExtension { - override fun process(module: Module, name: String, cfg: Map) { + override fun process(module: Module, name: String, cfg: Map) { val cfgType = ConfigurationTypeUtil.findConfigurationType( ApplicationConfigurationType::class.java) val runManager = RunManager.getInstance(module.project) val runnerAndConfigurationSettings = runManager.createConfiguration(name, cfgType.configurationFactories[0]) val appConfig = runnerAndConfigurationSettings.configuration as ApplicationConfiguration - appConfig.MAIN_CLASS_NAME = cfg["mainClass"] - appConfig.VM_PARAMETERS = cfg["jvmArgs"] + appConfig.MAIN_CLASS_NAME = cfg["mainClass"] as? String + appConfig.VM_PARAMETERS = cfg["jvmArgs"] as? String appConfig.setModule(module) runManager.addConfiguration(runnerAndConfigurationSettings) } - override fun process(project: Project, name: String, cfg: Map) {} + override fun process(project: Project, name: String, cfg: Map) {} override fun canHandle(typeName: String): Boolean = typeName == "application" } \ No newline at end of file diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java index e5d012becb1a..c266cebb9363 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.externalSystem.util; +import com.intellij.build.DefaultBuildDescriptor; import com.intellij.build.SyncViewManager; import com.intellij.build.events.BuildEvent; import com.intellij.build.events.EventResult; @@ -34,6 +35,8 @@ import com.intellij.execution.process.ProcessOutputTypes; import com.intellij.execution.rmi.RemoteUtil; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ProgramRunner; +import com.intellij.execution.ui.ExecutionConsole; +import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.icons.AllIcons; import com.intellij.notification.Notification; import com.intellij.notification.NotificationGroup; @@ -47,6 +50,7 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.externalSystem.ExternalSystemManager; +import com.intellij.openapi.externalSystem.execution.ExternalSystemExecutionConsoleManager; import com.intellij.openapi.externalSystem.importing.ImportSpec; import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder; import com.intellij.openapi.externalSystem.model.*; @@ -56,10 +60,7 @@ import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.model.task.*; import com.intellij.openapi.externalSystem.model.task.event.*; import com.intellij.openapi.externalSystem.service.ImportCanceledException; -import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemTaskConfigurationType; -import com.intellij.openapi.externalSystem.service.execution.ExternalSystemProcessHandler; -import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; -import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; +import com.intellij.openapi.externalSystem.service.execution.*; import com.intellij.openapi.externalSystem.service.internal.ExternalSystemProcessingManager; import com.intellij.openapi.externalSystem.service.internal.ExternalSystemResolveProjectTask; import com.intellij.openapi.externalSystem.service.notification.ExternalSystemNotificationManager; @@ -433,6 +434,16 @@ public class ExternalSystemUtil { closeInput(); } }; + + final ExternalSystemExecutionConsoleManager + consoleManager = getConsoleManagerFor(myTask); + + final ExecutionConsole consoleView = + consoleManager.attachExecutionConsole(project, myTask, null, processHandler); + if (consoleView != null) { + Disposer.register(project, consoleView); + } + ExternalSystemTaskNotificationListenerAdapter taskListener = new ExternalSystemTaskNotificationListenerAdapter() { @Override public void onStart(@NotNull ExternalSystemTaskId id, String workingDir) { @@ -454,9 +465,20 @@ public class ExternalSystemUtil { rerunImportAction.getTemplatePresentation().setDescription(ExternalSystemBundle.message("action.refresh.project.description", systemId)); rerunImportAction.getTemplatePresentation().setIcon(AllIcons.Actions.Refresh); ServiceManager.getService(project, SyncViewManager.class).onEvent( - new StartBuildEventImpl(id, projectName, eventTime, "syncing...") + new StartBuildEventImpl(new DefaultBuildDescriptor(id, projectName, externalProjectPath, eventTime), "syncing...") .withProcessHandler(processHandler, null) .withRestartAction(rerunImportAction) + .withContentDescriptorSupplier(() -> { + if (consoleView == null) { + return null; + } + else { + RunContentDescriptor contentDescriptor = new RunContentDescriptor(consoleView, processHandler, consoleView.getComponent(), "Sync"); + contentDescriptor.setActivateToolWindowWhenAdded(reportRefreshError); + contentDescriptor.setAutoFocusContent(true); + return contentDescriptor; + } + }) ); } @@ -467,49 +489,7 @@ public class ExternalSystemUtil { @Override public void onFailure(@NotNull ExternalSystemTaskId id, @NotNull Exception e) { - ExternalSystemNotificationManager notificationManager = ExternalSystemNotificationManager.getInstance(project); - NotificationData notificationData = notificationManager.createNotification(e, projectName, externalSystemId, project); - FailureResultImpl failureResult; - if (notificationData.isBalloonNotification()) { - notificationManager.showNotification(externalSystemId, notificationData); - failureResult = new FailureResultImpl(e); - } - else { - NotificationGroup group; - if (notificationData.getBalloonGroup() == null) { - ExternalProjectsView externalProjectsView = - ExternalProjectsManagerImpl.getInstance(project).getExternalProjectsView(externalSystemId); - group = externalProjectsView instanceof ExternalProjectsViewImpl ? - ((ExternalProjectsViewImpl)externalProjectsView).getNotificationGroup() : null; - } - else { - final NotificationGroup registeredGroup = NotificationGroup.findRegisteredGroup(notificationData.getBalloonGroup()); - group = registeredGroup != null ? registeredGroup : NotificationGroup.balloonGroup(notificationData.getBalloonGroup()); - } - if (group != null) { - int line = notificationData.getLine() - 1; - int column = notificationData.getColumn() - 1; - final VirtualFile virtualFile = - notificationData.getFilePath() != null ? findLocalFileByPath(notificationData.getFilePath()) : null; - - final Navigatable navigatable; - if (notificationData.getNavigatable() == null || notificationData.getNavigatable() instanceof NonNavigatable) { - navigatable = virtualFile != null ? new OpenFileDescriptor(project, virtualFile, line, column) : NonNavigatable.INSTANCE; - } - else { - navigatable = notificationData.getNavigatable(); - } - - final Notification notification = group.createNotification( - notificationData.getTitle(), notificationData.getMessage(), - notificationData.getNotificationCategory().getNotificationType(), notificationData.getListener()); - failureResult = new FailureResultImpl(list(new FailureImpl( - notificationData.getMessage(), e, new NotificationDataImpl(notification, notificationData.getListener(), navigatable)))); - } - else { - failureResult = new FailureResultImpl(e); - } - } + FailureResultImpl failureResult = createFailureResult(e, projectName, externalSystemId, project); ServiceManager.getService(project, SyncViewManager.class).onEvent( new FinishBuildEventImpl(id, null, System.currentTimeMillis(), "sync failed", failureResult)); String exceptionMessage = ExceptionUtil.getMessage(e); @@ -607,6 +587,57 @@ public class ExternalSystemUtil { } } + @NotNull + public static FailureResultImpl createFailureResult(@NotNull Exception exception, + String projectName, + ProjectSystemId externalSystemId, + Project project) { + ExternalSystemNotificationManager notificationManager = ExternalSystemNotificationManager.getInstance(project); + NotificationData notificationData = notificationManager.createNotification(exception, projectName, externalSystemId, project); + FailureResultImpl failureResult; + if (notificationData.isBalloonNotification()) { + notificationManager.showNotification(externalSystemId, notificationData); + failureResult = new FailureResultImpl(exception); + } + else { + NotificationGroup group; + if (notificationData.getBalloonGroup() == null) { + ExternalProjectsView externalProjectsView = + ExternalProjectsManagerImpl.getInstance(project).getExternalProjectsView(externalSystemId); + group = externalProjectsView instanceof ExternalProjectsViewImpl ? + ((ExternalProjectsViewImpl)externalProjectsView).getNotificationGroup() : null; + } + else { + final NotificationGroup registeredGroup = NotificationGroup.findRegisteredGroup(notificationData.getBalloonGroup()); + group = registeredGroup != null ? registeredGroup : NotificationGroup.balloonGroup(notificationData.getBalloonGroup()); + } + if (group != null) { + int line = notificationData.getLine() - 1; + int column = notificationData.getColumn() - 1; + final VirtualFile virtualFile = + notificationData.getFilePath() != null ? findLocalFileByPath(notificationData.getFilePath()) : null; + + final Navigatable navigatable; + if (notificationData.getNavigatable() == null || notificationData.getNavigatable() instanceof NonNavigatable) { + navigatable = virtualFile != null ? new OpenFileDescriptor(project, virtualFile, line, column) : NonNavigatable.INSTANCE; + } + else { + navigatable = notificationData.getNavigatable(); + } + + final Notification notification = group.createNotification( + notificationData.getTitle(), notificationData.getMessage(), + notificationData.getNotificationCategory().getNotificationType(), notificationData.getListener()); + failureResult = new FailureResultImpl(list(new FailureImpl( + notificationData.getMessage(), exception, new NotificationDataImpl(notification, notificationData.getListener(), navigatable)))); + } + else { + failureResult = new FailureResultImpl(exception); + } + } + return failureResult; + } + public static BuildEvent convert(ExternalSystemTaskExecutionEvent taskExecutionEvent) { ExternalSystemProgressEvent progressEvent = taskExecutionEvent.getProgressEvent(); String displayName = progressEvent.getDescriptor().getDisplayName(); @@ -981,6 +1012,19 @@ public class ExternalSystemUtil { project, projectSystemId, linkedProjectSettings.getExternalProjectPath()); } + @NotNull + public static ExternalSystemExecutionConsoleManager + getConsoleManagerFor(@NotNull ExternalSystemTask task) { + for (ExternalSystemExecutionConsoleManager executionConsoleManager : ExternalSystemExecutionConsoleManager.EP_NAME.getExtensions()) { + if (executionConsoleManager.isApplicableFor(task)) { + //noinspection unchecked + return executionConsoleManager; + } + } + + return new DefaultExternalSystemExecutionConsoleManager(); + } + public static void invokeLater(Project p, Runnable r) { invokeLater(p, ModalityState.defaultModalityState(), r); diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/file/impl/ResolveScopeManagerImpl.java b/platform/indexing-impl/src/com/intellij/psi/impl/file/impl/ResolveScopeManagerImpl.java index 971149105ef2..a43183db02c5 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/file/impl/ResolveScopeManagerImpl.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/file/impl/ResolveScopeManagerImpl.java @@ -56,27 +56,25 @@ public class ResolveScopeManagerImpl extends ResolveScopeManager { myManager = psiManager; myAdditionalIndexableFileSet = new AdditionalIndexableFileSet(project); - myDefaultResolveScopesCache = ConcurrentFactoryMap.createMap(key-> { + myDefaultResolveScopesCache = ConcurrentFactoryMap.createMap( + key -> { GlobalSearchScope scope = null; - for(ResolveScopeProvider resolveScopeProvider: ResolveScopeProvider.EP_NAME.getExtensions()) { + for (ResolveScopeProvider resolveScopeProvider : ResolveScopeProvider.EP_NAME.getExtensions()) { scope = resolveScopeProvider.getResolveScope(key, myProject); if (scope != null) break; } if (scope == null) scope = getInherentResolveScope(key); for (ResolveScopeEnlarger enlarger : ResolveScopeEnlarger.EP_NAME.getExtensions()) { - final SearchScope extra = enlarger.getAdditionalResolveScope(key, myProject); + SearchScope extra = enlarger.getAdditionalResolveScope(key, myProject); if (extra != null) { scope = scope.union(extra); } } - return scope; }, + ContainerUtil::createConcurrentWeakKeySoftValueMap); - ContainerUtil::createConcurrentWeakKeySoftValueMap - - ); - ((PsiManagerImpl) psiManager).registerRunnableToRunOnChange(myDefaultResolveScopesCache::clear); + ((PsiManagerImpl)psiManager).registerRunnableToRunOnChange(myDefaultResolveScopesCache::clear); } private GlobalSearchScope getResolveScopeFromProviders(@NotNull final VirtualFile vFile) { @@ -98,7 +96,7 @@ public class ResolveScopeManagerImpl extends ResolveScopeManager { } return allScope; } - + return LibraryScopeCache.getInstance(myProject).getLibraryScope(projectFileIndex.getOrderEntriesForFile(vFile)); } @@ -217,4 +215,4 @@ public class ResolveScopeManagerImpl extends ResolveScopeManager { private static Set asSet(final Collection collection) { return collection instanceof Set ? (Set)collection : newTroveSet(collection); } -} +} \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/FixingLayoutPlainMatcher.java b/platform/lang-api/src/com/intellij/codeInsight/completion/FixingLayoutPlainMatcher.java new file mode 100644 index 000000000000..b5499553b4ce --- /dev/null +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/FixingLayoutPlainMatcher.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.codeStyle.FixingLayoutMatcher; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class FixingLayoutPlainMatcher extends PrefixMatcher { + @Nullable private final String myAlternativePrefix; + + public FixingLayoutPlainMatcher(String prefix) { + super(prefix); + myAlternativePrefix = FixingLayoutMatcher.fixLayout(prefix); + } + + @Override + public boolean isStartMatch(String name) { + return StringUtil.startsWithIgnoreCase(name, getPrefix()) || + myAlternativePrefix != null && StringUtil.startsWithIgnoreCase(name, myAlternativePrefix); + } + + @Override + public boolean prefixMatches(@NotNull String name) { + return StringUtil.containsIgnoreCase(name, getPrefix()) || + myAlternativePrefix != null && StringUtil.containsIgnoreCase(name, myAlternativePrefix); + } + + @NotNull + @Override + public PrefixMatcher cloneWithPrefix(@NotNull String prefix) { + return new FixingLayoutPlainMatcher(prefix); + } +} diff --git a/platform/lang-api/src/com/intellij/facet/frameworks/LibrariesDownloadAssistant.java b/platform/lang-api/src/com/intellij/facet/frameworks/LibrariesDownloadAssistant.java index 71b0c9fb04ab..d82e1bdb120a 100644 --- a/platform/lang-api/src/com/intellij/facet/frameworks/LibrariesDownloadAssistant.java +++ b/platform/lang-api/src/com/intellij/facet/frameworks/LibrariesDownloadAssistant.java @@ -6,9 +6,7 @@ import com.intellij.facet.frameworks.beans.Artifacts; import com.intellij.facet.ui.libraries.LibraryInfo; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import com.intellij.util.net.HttpConfigurable; @@ -79,7 +77,7 @@ public class LibrariesDownloadAssistant { if (allArtifacts != null) { final Artifact[] vers = allArtifacts.getArtifacts(); if (vers != null) { - versions.addAll(Arrays.asList(vers)); + ContainerUtil.addAll(versions, Arrays.asList(vers)); } } } diff --git a/platform/lang-api/src/com/intellij/facet/frameworks/ui/LibrariesDownloadUiUtil.java b/platform/lang-api/src/com/intellij/facet/frameworks/ui/LibrariesDownloadUiUtil.java index ec41a4b819c5..010de0dcce9c 100644 --- a/platform/lang-api/src/com/intellij/facet/frameworks/ui/LibrariesDownloadUiUtil.java +++ b/platform/lang-api/src/com/intellij/facet/frameworks/ui/LibrariesDownloadUiUtil.java @@ -19,6 +19,7 @@ import com.intellij.facet.frameworks.LibrariesDownloadAssistant; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.ui.CollectionComboBoxModel; +import com.intellij.util.SmartList; import com.intellij.util.ui.update.Activatable; import com.intellij.util.ui.update.UiNotifyConnector; import org.jetbrains.annotations.NotNull; @@ -26,7 +27,6 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.net.URL; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** @@ -73,8 +73,7 @@ public class LibrariesDownloadUiUtil { final URL... localUrls) { final ModalityState state = ModalityState.current(); ApplicationManager.getApplication().executeOnPooledThread(() -> { - final List newItems = new ArrayList<>(); - newItems.addAll(Arrays.asList(LibrariesDownloadAssistant.getVersions(groupId, localUrls))); + final List newItems = new SmartList<>(LibrariesDownloadAssistant.getVersions(groupId, localUrls)); ApplicationManager.getApplication().invokeLater(() -> { items.clear(); diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/ProjectCodeStyleSettingsManager.java b/platform/lang-api/src/com/intellij/psi/codeStyle/ProjectCodeStyleSettingsManager.java index 49cc99e428ce..2992f41ed7bd 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/ProjectCodeStyleSettingsManager.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/ProjectCodeStyleSettingsManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -21,7 +21,6 @@ import com.intellij.notification.Notification; import com.intellij.notification.NotificationDisplayType; import com.intellij.notification.NotificationGroup; import com.intellij.notification.NotificationType; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.application.ApplicationManager; @@ -31,6 +30,7 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.util.containers.ContainerUtil; import org.jdom.Element; @@ -177,7 +177,7 @@ public class ProjectCodeStyleSettingsManager extends CodeStyleSettingsManager { } } - private static class ShowMoreInfoAction extends AnAction { + private static class ShowMoreInfoAction extends DumbAwareAction { public ShowMoreInfoAction() { super("More info"); } diff --git a/platform/lang-impl/src/com/intellij/analysis/BaseAnalysisActionDialog.java b/platform/lang-impl/src/com/intellij/analysis/BaseAnalysisActionDialog.java index b40950c50cf3..d326e174e001 100644 --- a/platform/lang-impl/src/com/intellij/analysis/BaseAnalysisActionDialog.java +++ b/platform/lang-impl/src/com/intellij/analysis/BaseAnalysisActionDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -96,6 +96,14 @@ public class BaseAnalysisActionDialog extends DialogWrapper { @NotNull AnalysisUIOptions analysisUIOptions, @Nullable PsiElement context) { super(true); + //noinspection BoundFieldAssignment + myGroup = new ButtonGroup(); + myGroup.add(myProjectButton); + myGroup.add(myModuleButton); + myGroup.add(myUncommitedFilesButton); + myGroup.add(myFileButton); + myGroup.add(myCustomScopeButton); + Disposer.register(myDisposable, myScopeCombo); myAnalysisOptions = analysisUIOptions; myContext = context; 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 036c4c3a2333..7755eb13cf56 100644 --- a/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java @@ -21,6 +21,7 @@ import com.intellij.lang.Language; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.TransactionGuard; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; @@ -178,22 +179,23 @@ public abstract class CodeStyleAbstractPanel implements Disposable { return; } - if (myLastDocumentModificationStamp != myEditor.getDocument().getModificationStamp()) { - myTextToReformat = myEditor.getDocument().getText(); - } - else if (useDefaultSample || myTextToReformat == null) { - myTextToReformat = getPreviewText(); - } + Project project = ProjectUtil.guessCurrentProject(getPanel()); + TransactionGuard.submitTransaction(project, () -> { + if (myLastDocumentModificationStamp != myEditor.getDocument().getModificationStamp()) { + myTextToReformat = myEditor.getDocument().getText(); + } + else if (useDefaultSample || myTextToReformat == null) { + myTextToReformat = getPreviewText(); + } - int currOffs = myEditor.getScrollingModel().getVerticalScrollOffset(); + int currOffs = myEditor.getScrollingModel().getVerticalScrollOffset(); + CommandProcessor.getInstance().executeCommand(project, () -> replaceText(project), null, null); - final Project finalProject = ProjectUtil.guessCurrentProject(getPanel()); - CommandProcessor.getInstance().executeCommand(finalProject, () -> replaceText(finalProject), null, null); - - myEditor.getSettings().setRightMargin(getAdjustedRightMargin()); - myEditor.getSettings().setSoftMargins(getCurrentSoftMargins()); - myLastDocumentModificationStamp = myEditor.getDocument().getModificationStamp(); - myEditor.getScrollingModel().scrollVertically(currOffs); + myEditor.getSettings().setRightMargin(getAdjustedRightMargin()); + myEditor.getSettings().setSoftMargins(getCurrentSoftMargins()); + myLastDocumentModificationStamp = myEditor.getDocument().getModificationStamp(); + myEditor.getScrollingModel().scrollVertically(currOffs); + }); } private List getCurrentSoftMargins() { diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java index c6f4a7fca57f..61b4cd8165fc 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java @@ -30,6 +30,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.application.ApplicationNamesInfo; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.colors.*; import com.intellij.openapi.editor.colors.ex.DefaultColorSchemesManager; import com.intellij.openapi.editor.colors.impl.*; @@ -79,6 +80,8 @@ import static com.intellij.openapi.actionSystem.PlatformDataKeys.CONTEXT_COMPONE public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract implements EditorOptionsProvider, SchemesModel { + private static final Logger LOG = Logger.getInstance(ColorAndFontOptions.class); + public static final String ID = "reference.settingsdialog.IDE.editor.colors"; public static final String FONT_CONFIGURABLE_NAME = "Color Scheme Font"; @@ -604,6 +607,7 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract private static void initDescriptions(@NotNull ColorAndFontDescriptorsProvider provider, @NotNull List descriptions, @NotNull MyColorScheme scheme) { + String className = provider.getClass().getName(); String group = provider.getDisplayName(); List attributeDescriptors = ColorSettingsUtil.getAllAttributeDescriptors(provider); if (provider instanceof RainbowColorSettingsPage) { @@ -614,11 +618,13 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract descriptions.add(d); } for (AttributesDescriptor descriptor : attributeDescriptors) { + LOG.assertTrue(descriptor != null, className); SchemeTextAttributesDescription d = new SchemeTextAttributesDescription( descriptor.getDisplayName(), group, descriptor.getKey(), scheme, null, null); descriptions.add(d); } for (ColorDescriptor descriptor : provider.getColorDescriptors()) { + LOG.assertTrue(descriptor != null, className); EditorSettingColorDescription d = new EditorSettingColorDescription( descriptor.getDisplayName(), group, descriptor.getKey(), descriptor.getKind(), scheme); descriptions.add(d); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/FilePathCompletionContributor.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/FilePathCompletionContributor.java index 84b68a336f6a..0b4db7844b8f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/FilePathCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/FilePathCompletionContributor.java @@ -48,6 +48,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.ProjectScope; import com.intellij.util.ArrayUtil; import com.intellij.util.ProcessingContext; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -218,7 +219,7 @@ public class FilePathCompletionContributor extends CompletionContributor { final ChooseByNameContributor[] nameContributors = ChooseByNameContributor.FILE_EP_NAME.getExtensions(); for (final ChooseByNameContributor contributor : nameContributors) { try { - names.addAll(Arrays.asList(contributor.getNames(project, false))); + ContainerUtil.addAll(names, contributor.getNames(project, false)); } catch (ProcessCanceledException ex) { // index corruption detected, ignore diff --git a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java index c92b102d3158..d6a620d33333 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java @@ -23,6 +23,7 @@ import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ex.ApplicationManagerEx; +import com.intellij.openapi.application.impl.ApplicationImpl; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; @@ -42,6 +43,7 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.fileTypes.SyntaxHighlighter; import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; +import com.intellij.openapi.progress.util.ProgressIndicatorUtils; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Conditions; @@ -117,42 +119,45 @@ public class BraceHighlightingHandler { final DumbAwareRunnable removeEditorFromProcessed = () -> PROCESSED_EDITORS.remove(editor); ApplicationManager.getApplication().executeOnPooledThread(() -> { - if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(() -> { - if (!isValidEditor(editor)) { - ApplicationManager.getApplication().invokeLater(removeEditorFromProcessed); - return; - } - @SuppressWarnings("ConstantConditions") // the `project` is valid after the `isValidEditor` call - @NotNull final Project project = editor.getProject(); + if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(() -> + ((ApplicationImpl)ApplicationManager.getApplication()).executeByImpatientReader(()-> + ProgressIndicatorUtils.runInReadActionWithWriteActionPriority(()->{ + if (!isValidEditor(editor)) { + ApplicationManager.getApplication().invokeLater(removeEditorFromProcessed); + return; + } + @SuppressWarnings("ConstantConditions") // the `project` is valid after the `isValidEditor` call + @NotNull final Project project = editor.getProject(); - final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project); - final PsiFile injected; - try { - if (psiFile instanceof PsiBinaryFile || !isValidFile(psiFile)) { - injected = null; - } - else { - injected = getInjectedFileIfAny(editor, project, offset, psiFile, alarm); - } - } - catch (RuntimeException e) { - // Reset processing flag in case of unexpected exception. - ApplicationManager.getApplication().invokeLater(removeEditorFromProcessed); - throw e; - } - ApplicationManager.getApplication().invokeLater((DumbAwareRunnable)() -> { + final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project); + final PsiFile injected; try { - if (isValidEditor(editor) && isValidFile(injected)) { - Editor newEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injected); - BraceHighlightingHandler handler = new BraceHighlightingHandler(project, newEditor, alarm, injected); - processor.process(handler); + if (psiFile instanceof PsiBinaryFile || !isValidFile(psiFile)) { + injected = null; + } + else { + injected = getInjectedFileIfAny(editor, project, offset, psiFile, alarm); } } - finally { - removeEditorFromProcessed.run(); + catch (RuntimeException e) { + // Reset processing flag in case of unexpected exception. + ApplicationManager.getApplication().invokeLater(removeEditorFromProcessed); + throw e; } - }, modalityState); - })) { + ApplicationManager.getApplication().invokeLater((DumbAwareRunnable)() -> { + try { + if (isValidEditor(editor) && isValidFile(injected)) { + Editor newEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injected); + BraceHighlightingHandler handler = new BraceHighlightingHandler(project, newEditor, alarm, injected); + processor.process(handler); + } + } + finally { + removeEditorFromProcessed.run(); + } + }, modalityState); + }) + ))) { // write action is queued in AWT. restart after it's finished ApplicationManager.getApplication().invokeLater(() -> { removeEditorFromProcessed.run(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java index e2253945a0fe..ec0c9b18c352 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java @@ -309,6 +309,14 @@ public class ParameterInfoController implements Disposable { if (elementForUpdating != null) { myHandler.updateParameterInfo(elementForUpdating, context); + if (mySingleParameterInfo) { + if (myComponent.getCurrentParameterIndex() == -1 && myHint.isVisible()) { + myHint.hide(); + } + else if (myComponent.getCurrentParameterIndex() != -1 && !myHint.isVisible()) { + AutoPopupController.getInstance(myProject).autoPopupParameterInfo(myEditor, null); + } + } if (!myDisposed && myHint.isVisible() && !myEditor.isDisposed() && (myEditor.getComponent().getRootPane() != null || ApplicationManager.getApplication().isUnitTestMode())) { myComponent.update(mySingleParameterInfo); diff --git a/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java b/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java index b7b4d5ec0617..836dd74fc0f3 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java @@ -122,7 +122,14 @@ public class RunConfigurationsComboBoxAction extends ComboBoxAction implements D @Override public JComponent createCustomComponent(final Presentation presentation) { - ComboBoxButton button = createComboBoxButton(presentation); + ComboBoxButton button = new ComboBoxButton(presentation) { + @Override + public Dimension getPreferredSize() { + Dimension d = super.getPreferredSize(); + d.width = Math.max(d.width, JBUI.scale(75)); + return d; + } + }; NonOpaquePanel panel = new NonOpaquePanel(new BorderLayout()); panel.setBorder(JBUI.Borders.emptyRight(2)); panel.add(button); diff --git a/platform/lang-impl/src/com/intellij/execution/rmi/RemoteProcessSupport.java b/platform/lang-impl/src/com/intellij/execution/rmi/RemoteProcessSupport.java index aaa7546cb12b..4b2322f8e246 100644 --- a/platform/lang-impl/src/com/intellij/execution/rmi/RemoteProcessSupport.java +++ b/platform/lang-impl/src/com/intellij/execution/rmi/RemoteProcessSupport.java @@ -74,7 +74,14 @@ public abstract class RemoteProcessSupport { protected abstract String getName(Target target); - protected void logText(Parameters configuration, ProcessEvent event, Key outputType, Object info) { + protected void logText(@NotNull Parameters configuration, @NotNull ProcessEvent event, @NotNull Key outputType) { + String text = StringUtil.notNullize(event.getText()); + if (outputType == ProcessOutputTypes.STDERR) { + LOG.warn(text.trim()); + } + else { + LOG.debug(text.trim()); + } } public void stopAll() { @@ -308,18 +315,11 @@ public abstract class RemoteProcessSupport { @Override public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) { String text = StringUtil.notNullize(event.getText()); - if (outputType == ProcessOutputTypes.STDERR) { - LOG.warn(text.trim()); - } - else { - LOG.debug(text.trim()); - } - + logText(key.second, event, outputType); RunningInfo result = null; PendingInfo info; synchronized (myProcMap) { Info o = myProcMap.get(key); - logText(key.second, event, outputType, o); if (o instanceof PendingInfo) { info = (PendingInfo)o; if (outputType == ProcessOutputTypes.STDOUT) { diff --git a/platform/lang-impl/src/com/intellij/execution/ui/MacroComboBoxWithBrowseButton.java b/platform/lang-impl/src/com/intellij/execution/ui/MacroComboBoxWithBrowseButton.java index d0e67a5910ec..50742ae4b8c9 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/MacroComboBoxWithBrowseButton.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/MacroComboBoxWithBrowseButton.java @@ -91,7 +91,7 @@ public class MacroComboBoxWithBrowseButton extends ComponentWithBrowseButton> nameMatches = getFileNameCandidates(base, everywhere, sanitized, !pattern.startsWith("*")); - - MinusculeMatcher fullMatcher = NameUtil.buildMatcher("*" + StringUtil.replace(sanitized, "/", "*/*"), NameUtil.MatchingCaseSensitivity.NONE); - PathProximityComparator pathProximityComparator = getPathProximityComparator(); - - for (List group : nameMatches) { - if (!ContainerUtil.process(getFilesMatchingPath(pattern, everywhere, fullMatcher, pathProximityComparator, group), consumer)) { + NameGrouper grouper = new NameGrouper(sanitized.substring(sanitized.lastIndexOf('/') + 1)); + myModel.processNames(name -> grouper.processName(name), true); + while (true) { + SuffixMatches group = grouper.nextGroup(base); + if (group == null) return true; + if (!group.processFiles(pattern, sanitized, everywhere, consumer)) { return false; } } - - return true; } @NotNull @@ -108,7 +107,7 @@ public class GotoFileItemProvider extends DefaultChooseByNameItemProvider { private List getFilesMatchingPath(@NotNull String pattern, boolean everywhere, MinusculeMatcher fullMatcher, - PathProximityComparator pathProximityComparator, List fileNames) { + List fileNames) { List group = new ArrayList<>(); Map qualifierMatchingDegrees = new HashMap<>(); Map dirCloseness = new HashMap<>(); @@ -118,7 +117,7 @@ public class GotoFileItemProvider extends DefaultChooseByNameItemProvider { String fullName = myModel.getFullName(o); if (o instanceof PsiFileSystemItem && fullName != null) { FList fragments = fullMatcher.matchingFragments(fullName); - if (fragments != null) { + if (fragments != null && !fragments.isEmpty()) { group.add((PsiFileSystemItem)o); qualifierMatchingDegrees.put((PsiFileSystemItem)o, -fullMatcher.matchingDegree(fullName, false, fragments)); @@ -134,67 +133,163 @@ public class GotoFileItemProvider extends DefaultChooseByNameItemProvider { if (group.size() > 1) { Collections.sort(group, - Comparator.comparing(nesting::get). + Comparator.comparing(nesting::get). thenComparing(dirCloseness::get). thenComparing(qualifierMatchingDegrees::get). - thenComparing(pathProximityComparator). + thenComparing(getPathProximityComparator()). thenComparing(myModel::getFullName)); } return group; } - @NotNull - private List> getFileNameCandidates(@NotNull ChooseByNameBase base, - boolean everywhere, - String sanitized, boolean preferStartMatches) { - int start = Math.max(sanitized.lastIndexOf('/'), sanitized.lastIndexOf('\\')) + 1; - List partialNames = IntStreamEx.range(start, sanitized.length()).mapToObj(i -> sanitized.substring(i)).toList(); - List matchers = ContainerUtil.map(partialNames, s -> NameUtil.buildMatcher("*" + s, NameUtil.MatchingCaseSensitivity.NONE)); - List> matchingNames = ContainerUtil.map(partialNames, __ -> new ArrayList<>()); + /** + * @return Minimal {@code pos} such that {@code candidateName} can potentially match {@code namePattern.substring(pos)} + * (i.e. contains the same letters as a sub-sequence). + * Matching attempts with longer pattern substrings certainly will fail. + */ + private static int findMatchStartingPosition(String candidateName, String namePattern) { + int namePos = candidateName.length(); + for (int i = namePattern.length(); i > 0; i--) { + char c = namePattern.charAt(i - 1); + if (Character.isLetterOrDigit(c)) { + namePos = StringUtil.lastIndexOfIgnoreCase(candidateName, c, namePos - 1); + if (namePos < 0) { + return i; + } + } + } + return 0; + } - myModel.processNames(name -> { - for (int i = 0; i < partialNames.size(); i++) { - MatchResult result = matches(base, partialNames.get(i), matchers.get(i), name); - if (result != null) { - matchingNames.get(i).add(result); - break; + private class NameGrouper { + private final String namePattern; + @Nullable private final String alternativePattern; + + /** Names placed into buckets where the index of bucket == {@link #findMatchStartingPosition} */ + private final List> candidateNames; + + private int index = 0; + + NameGrouper(@NotNull String namePattern) { + this.namePattern = namePattern; + alternativePattern = FixingLayoutMatcher.fixLayout(namePattern); + candidateNames = IntStreamEx.range(0, namePattern.length()).mapToObj(__ -> (List)new ArrayList()).toList(); + } + + boolean processName(String name) { + ProgressManager.checkCanceled(); + int position = findMatchStartingPosition(name, namePattern); + if (position >= namePattern.length() && alternativePattern != null) { + position = findMatchStartingPosition(name, alternativePattern); + } + if (position < namePattern.length()) { + List list = candidateNames.get(position); + //noinspection SynchronizationOnLocalVariableOrMethodParameter + synchronized (list) { // names can be processed concurrently + list.add(name); } } return true; - }, everywhere); - - List> result = new ArrayList<>(); - for (int i = 0; i < partialNames.size(); i++) { - result.addAll(groupByMatchingDegree(matchingNames.get(i), partialNames.get(i), preferStartMatches)); } - return result; + + @Nullable + SuffixMatches nextGroup(ChooseByNameBase base) { + if (index >= namePattern.length()) return null; + + SuffixMatches matches = new SuffixMatches(namePattern.substring(index)); + for (String name : candidateNames.get(index)) { + if (!matches.matchName(base, name) && index + 1 < namePattern.length()) { + candidateNames.get(index + 1).add(name); // try later with a shorter matcher + } + } + candidateNames.set(index, null); + index++; + return matches; + } } - private static List> groupByMatchingDegree(List nameMatches, - String namePattern, boolean preferStartMatches) { - if (nameMatches.isEmpty()) return Collections.emptyList(); + private class SuffixMatches { + final String patternSuffix; + final MinusculeMatcher matcher; + final List matchingNames = new ArrayList<>(); - List> groups = new ArrayList<>(); - - Comparator comparator = (mr1, mr2) -> { - boolean exactPrefix1 = namePattern.equalsIgnoreCase(mr1.elementName); - boolean exactPrefix2 = namePattern.equalsIgnoreCase(mr2.elementName); - if (exactPrefix1 != exactPrefix2) return exactPrefix1 ? -1 : 1; - return mr1.compareDegrees(mr2, preferStartMatches); - }; - Collections.sort(nameMatches, comparator); - - List group = ContainerUtil.newArrayList(nameMatches.get(0).elementName); - for (int j = 1; j < nameMatches.size(); j++) { - MatchResult current = nameMatches.get(j); - if (comparator.compare(nameMatches.get(j - 1), current) == 0) { - group.add(current.elementName); - } else { - groups.add(group); - group = ContainerUtil.newArrayList(current.elementName); - } + SuffixMatches(String patternSuffix) { + this.patternSuffix = patternSuffix; + matcher = NameUtil.buildMatcher("*" + patternSuffix, NameUtil.MatchingCaseSensitivity.NONE); } - groups.add(group); - return groups; + + @Override + public String toString() { + return "SuffixMatches{" + + "patternSuffix='" + patternSuffix + '\'' + + ", matchingNames=" + matchingNames + + '}'; + } + + boolean matchName(@NotNull ChooseByNameBase base, String name) { + MatchResult result = matches(base, patternSuffix, matcher, name); + if (result != null) { + matchingNames.add(result); + return true; + } + return false; + } + + boolean processFiles(@NotNull String pattern, String sanitizedPattern, boolean everywhere, Processor processor) { + MinusculeMatcher fullMatcher = NameUtil.buildMatcher("*" + StringUtil.replace(sanitizedPattern, "/", "*/*"), NameUtil.MatchingCaseSensitivity.NONE); + + boolean empty = true; + List> groups = groupByMatchingDegree(!pattern.startsWith("*")); + for (List group : groups) { + List files = getFilesMatchingPath(pattern, everywhere, fullMatcher, group); + empty &= files.isEmpty(); + if (!ContainerUtil.process(files, processor)) { + return false; + } + } + + if (!empty) { + return false; // don't process expensive worse matches + } + + if (!everywhere && hasSuggestionsOutsideProject(pattern, fullMatcher, groups)) { + // let the framework switch to searching outside project to display these well-matching suggestions + // instead of worse-matching ones in project (that are very expensive to calculate) + return false; + } + return true; + } + + private boolean hasSuggestionsOutsideProject(@NotNull String pattern, MinusculeMatcher fullMatcher, List> groups) { + return ContainerUtil.exists(groups, group -> !getFilesMatchingPath(pattern, true, fullMatcher, group).isEmpty()); + } + + private List> groupByMatchingDegree(boolean preferStartMatches) { + if (matchingNames.isEmpty()) return Collections.emptyList(); + + List> groups = new ArrayList<>(); + + Comparator comparator = (mr1, mr2) -> { + boolean exactPrefix1 = patternSuffix.equalsIgnoreCase(mr1.elementName); + boolean exactPrefix2 = patternSuffix.equalsIgnoreCase(mr2.elementName); + if (exactPrefix1 != exactPrefix2) return exactPrefix1 ? -1 : 1; + return mr1.compareDegrees(mr2, preferStartMatches); + }; + Collections.sort(matchingNames, comparator); + + List group = ContainerUtil.newArrayList(matchingNames.get(0).elementName); + for (int j = 1; j < matchingNames.size(); j++) { + MatchResult current = matchingNames.get(j); + if (comparator.compare(matchingNames.get(j - 1), current) == 0) { + group.add(current.elementName); + } else { + groups.add(group); + group = ContainerUtil.newArrayList(current.elementName); + } + } + groups.add(group); + return groups; + } + } } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java b/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java index e2c79cffef46..581c15160c3f 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java @@ -76,7 +76,7 @@ public abstract class ProjectViewPsiTreeChangeListener extends PsiTreeChangeAdap protected void childrenChanged(PsiElement parent, final boolean stopProcessingForThisModificationCount) { if (parent instanceof PsiDirectory && isFlattenPackages()){ - getUpdater().addSubtreeToUpdate(getRootNode()); + addSubtreeToUpdateByRoot(); return; } @@ -97,7 +97,7 @@ public abstract class ProjectViewPsiTreeChangeListener extends PsiTreeChangeAdap } } - if (getUpdater().addSubtreeToUpdateByElement(parent)) { + if (addSubtreeToUpdateByElement(parent)) { break; } @@ -110,28 +110,37 @@ public abstract class ProjectViewPsiTreeChangeListener extends PsiTreeChangeAdap public void propertyChanged(@NotNull PsiTreeChangeEvent event) { String propertyName = event.getPropertyName(); PsiElement element = event.getElement(); - DefaultMutableTreeNode rootNode = getRootNode(); - AbstractTreeUpdater updater = getUpdater(); if (propertyName.equals(PsiTreeChangeEvent.PROP_ROOTS)) { - updater.addSubtreeToUpdate(rootNode); + addSubtreeToUpdateByRoot(); } else if (propertyName.equals(PsiTreeChangeEvent.PROP_WRITABLE)){ - if (!updater.addSubtreeToUpdateByElement(element) && element instanceof PsiFile) { - updater.addSubtreeToUpdateByElement(((PsiFile)element).getContainingDirectory()); + if (!addSubtreeToUpdateByElement(element) && element instanceof PsiFile) { + addSubtreeToUpdateByElement(((PsiFile)element).getContainingDirectory()); } } else if (propertyName.equals(PsiTreeChangeEvent.PROP_FILE_NAME) || propertyName.equals(PsiTreeChangeEvent.PROP_DIRECTORY_NAME)){ if (element instanceof PsiDirectory && isFlattenPackages()){ - updater.addSubtreeToUpdate(rootNode); + addSubtreeToUpdateByRoot(); return; } final PsiElement parent = element.getParent(); - if (parent == null || !updater.addSubtreeToUpdateByElement(parent)) { - updater.addSubtreeToUpdateByElement(element); + if (parent == null || !addSubtreeToUpdateByElement(parent)) { + addSubtreeToUpdateByElement(element); } } else if (propertyName.equals(PsiTreeChangeEvent.PROP_FILE_TYPES)){ - updater.addSubtreeToUpdate(rootNode); + addSubtreeToUpdateByRoot(); } } + + protected void addSubtreeToUpdateByRoot() { + AbstractTreeUpdater updater = getUpdater(); + DefaultMutableTreeNode root = getRootNode(); + if (updater != null && root != null) updater.addSubtreeToUpdate(root); + } + + protected boolean addSubtreeToUpdateByElement(PsiElement element) { + AbstractTreeUpdater updater = getUpdater(); + return updater != null && updater.addSubtreeToUpdateByElement(element); + } } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java index 1ead863e72a1..54e27f08921d 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java @@ -20,11 +20,11 @@ import com.intellij.ide.DataManager; import com.intellij.ide.PsiCopyPasteManager; import com.intellij.ide.projectView.BaseProjectTreeBuilder; import com.intellij.ide.projectView.PresentationData; -import com.intellij.ide.projectView.ProjectView; import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; import com.intellij.ide.ui.customization.CustomizationUtil; import com.intellij.ide.util.treeView.AbstractTreeBuilder; import com.intellij.ide.util.treeView.AbstractTreeUpdater; +import com.intellij.ide.util.treeView.NodeDescriptor; import com.intellij.ide.util.treeView.PresentableNodeDescriptor; import com.intellij.ide.util.treeView.TreeBuilderUtil; import com.intellij.openapi.actionSystem.ActionPlaces; @@ -64,6 +64,7 @@ import javax.swing.tree.TreeSelectionModel; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; +import java.util.Comparator; import java.util.StringTokenizer; public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane { @@ -104,8 +105,7 @@ public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane setTreeBuilder(treeBuilder); } else { - myAsyncSupport = new AsyncProjectViewSupport(this, myProject, myTree, myTreeStructure, - new GroupByTypeComparator(ProjectView.getInstance(myProject), getId())); + myAsyncSupport = new AsyncProjectViewSupport(this, myProject, myTree, myTreeStructure, createComparator()); } initTree(); @@ -132,8 +132,15 @@ public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane return myComponent; } + @Override + protected void installComparator(AbstractTreeBuilder builder, Comparator comparator) { + if (myAsyncSupport != null) myAsyncSupport.setComparator(comparator); + super.installComparator(builder, comparator); + } + @Override public final void dispose() { + myAsyncSupport = null; myComponent = null; super.dispose(); } @@ -193,12 +200,13 @@ public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane final ArrayList selectionPaths = new ArrayList<>(); Runnable afterUpdate; final ActionCallback cb = new ActionCallback(); - if (restoreExpandedPaths) { - TreeBuilderUtil.storePaths(getTreeBuilder(), (DefaultMutableTreeNode)myTree.getModel().getRoot(), pathsToExpand, selectionPaths, true); + AbstractTreeBuilder builder = getTreeBuilder(); + if (restoreExpandedPaths && builder != null) { + TreeBuilderUtil.storePaths(builder, (DefaultMutableTreeNode)myTree.getModel().getRoot(), pathsToExpand, selectionPaths, true); afterUpdate = () -> { - if (myTree != null && getTreeBuilder() != null && !getTreeBuilder().isDisposed()) { + if (myTree != null && !builder.isDisposed()) { myTree.setSelectionPaths(new TreePath[0]); - TreeBuilderUtil.restorePaths(getTreeBuilder(), pathsToExpand, selectionPaths, true); + TreeBuilderUtil.restorePaths(builder, pathsToExpand, selectionPaths, true); } cb.setDone(); }; @@ -206,10 +214,12 @@ public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane else { afterUpdate = cb.createSetDoneRunnable(); } - if (getTreeBuilder() != null) { - getTreeBuilder().addSubtreeToUpdate(getTreeBuilder().getRootNode(), afterUpdate); + if (builder != null) { + builder.addSubtreeToUpdate(builder.getRootNode(), afterUpdate); + } + else if (myAsyncSupport != null) { + myAsyncSupport.updateAll(); } - //myTreeBuilder.updateFromRoot(); return cb; } @@ -221,12 +231,11 @@ public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane @NotNull public ActionCallback selectCB(Object element, VirtualFile file, boolean requestFocus) { if (file != null) { - if (getTreeBuilder() instanceof BaseProjectTreeBuilder) { - beforeSelect().doWhenDone(() -> { - UIUtil.invokeLaterIfNeeded( - () -> ((BaseProjectTreeBuilder)getTreeBuilder()).select(element, file, requestFocus) - ); - }); + AbstractTreeBuilder builder = getTreeBuilder(); + if (builder instanceof BaseProjectTreeBuilder) { + beforeSelect().doWhenDone(() -> UIUtil.invokeLaterIfNeeded(() -> { + if (!builder.isDisposed()) ((BaseProjectTreeBuilder)builder).select(element, file, requestFocus); + })); } else if (myAsyncSupport != null) { myAsyncSupport.select(myTree, element, file); @@ -239,7 +248,9 @@ public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane public ActionCallback beforeSelect() { // actually, getInitialized().doWhenDone() should be called by builder internally // this will be done in 2017 - return getTreeBuilder().getInitialized(); + AbstractTreeBuilder builder = getTreeBuilder(); + if (builder == null) return ActionCallback.DONE; + return builder.getInitialized(); } protected BaseProjectTreeBuilder createBuilder(DefaultTreeModel treeModel) { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java index 832ae60673f7..83d533e2babe 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java @@ -74,6 +74,7 @@ import java.awt.image.BufferedImage; import java.io.File; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; @@ -472,13 +473,20 @@ public abstract class AbstractProjectViewPane implements DataProvider, Disposabl } } + protected Comparator createComparator() { + return new GroupByTypeComparator(ProjectView.getInstance(myProject), getId()); + } + public void installComparator() { installComparator(getTreeBuilder()); } public void installComparator(AbstractTreeBuilder treeBuilder) { - final ProjectView projectView = ProjectView.getInstance(myProject); - treeBuilder.setNodeDescriptorComparator(new GroupByTypeComparator(projectView, getId())); + installComparator(treeBuilder, createComparator()); + } + + protected void installComparator(AbstractTreeBuilder builder, Comparator comparator) { + if (builder != null) builder.setNodeDescriptorComparator(comparator); } public JTree getTree() { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AsyncProjectViewSupport.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AsyncProjectViewSupport.java index 0499fab3d5f0..85057788eee2 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AsyncProjectViewSupport.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AsyncProjectViewSupport.java @@ -19,9 +19,10 @@ import com.intellij.ProjectTopics; import com.intellij.ide.CopyPasteUtil; import com.intellij.ide.bookmarks.Bookmark; import com.intellij.ide.bookmarks.BookmarksListener; -import com.intellij.ide.projectView.ProjectViewNode; +import com.intellij.ide.projectView.ProjectViewPsiTreeChangeListener; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.ide.util.treeView.AbstractTreeStructure; +import com.intellij.ide.util.treeView.AbstractTreeUpdater; import com.intellij.ide.util.treeView.NodeDescriptor; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; @@ -35,10 +36,9 @@ import com.intellij.openapi.vcs.FileStatusManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.problems.WolfTheProblemSolver; import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.ui.tree.AsyncTreeModel; import com.intellij.ui.tree.StructureTreeModel; -import com.intellij.ui.tree.TreeVisitor; +import com.intellij.util.SmartList; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; @@ -48,6 +48,7 @@ import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import java.util.Comparator; +import java.util.List; import static com.intellij.ide.util.treeView.TreeState.VISIT; import static com.intellij.util.ui.UIUtil.putClientProperty; @@ -56,7 +57,7 @@ class AsyncProjectViewSupport { private static final Logger LOG = Logger.getInstance(AbstractProjectViewPSIPane.class); private final StructureTreeModel myStructureTreeModel; private final AsyncTreeModel myAsyncTreeModel; - private final Project myProject; + private final PsiManager myPsiManager; public AsyncProjectViewSupport(Disposable parent, Project project, @@ -68,7 +69,7 @@ class AsyncProjectViewSupport { myStructureTreeModel.setComparator(comparator); myAsyncTreeModel = new AsyncTreeModel(myStructureTreeModel, true); myAsyncTreeModel.setRootImmediately(myStructureTreeModel.getRootImmediately()); - myProject = project; + myPsiManager = PsiManager.getInstance(project); tree.setModel(myAsyncTreeModel); Disposer.register(parent, myAsyncTreeModel); putClientProperty(tree, VISIT, visitor -> myAsyncTreeModel.visit(visitor, true)); @@ -100,65 +101,31 @@ class AsyncProjectViewSupport { //do nothing } }); - PsiManager.getInstance(project).addPsiTreeChangeListener(new PsiTreeChangeListener() { + myPsiManager.addPsiTreeChangeListener(new ProjectViewPsiTreeChangeListener(project) { @Override - public void beforeChildAddition(@NotNull PsiTreeChangeEvent event) { - updateAll();//TODO: + protected boolean isFlattenPackages() { + return structure instanceof AbstractProjectTreeStructure && ((AbstractProjectTreeStructure)structure).isFlattenPackages(); } @Override - public void beforeChildRemoval(@NotNull PsiTreeChangeEvent event) { - updateAll();//TODO: + protected AbstractTreeUpdater getUpdater() { + return null; } @Override - public void beforeChildReplacement(@NotNull PsiTreeChangeEvent event) { - updateAll();//TODO: + protected DefaultMutableTreeNode getRootNode() { + return null; } @Override - public void beforeChildMovement(@NotNull PsiTreeChangeEvent event) { - updateAll();//TODO: + protected void addSubtreeToUpdateByRoot() { + updateAll(); } @Override - public void beforeChildrenChange(@NotNull PsiTreeChangeEvent event) { - updateAll();//TODO: - } - - @Override - public void beforePropertyChange(@NotNull PsiTreeChangeEvent event) { - updateAll();//TODO: - } - - @Override - public void childAdded(@NotNull PsiTreeChangeEvent event) { - updateAll();//TODO: - } - - @Override - public void childRemoved(@NotNull PsiTreeChangeEvent event) { - updateAll();//TODO: - } - - @Override - public void childReplaced(@NotNull PsiTreeChangeEvent event) { - updateAll();//TODO: - } - - @Override - public void childrenChanged(@NotNull PsiTreeChangeEvent event) { - updateAll();//TODO: - } - - @Override - public void childMoved(@NotNull PsiTreeChangeEvent event) { - updateAll();//TODO: - } - - @Override - public void propertyChanged(@NotNull PsiTreeChangeEvent event) { - updateAll();//TODO: + protected boolean addSubtreeToUpdateByElement(PsiElement element) { + updateByElement(element); + return true; } }, parent); FileStatusManager.getInstance(project).addFileStatusListener(new FileStatusListener() { @@ -186,6 +153,10 @@ class AsyncProjectViewSupport { }, parent); } + public void setComparator(Comparator comparator) { + myStructureTreeModel.setComparator(comparator); + } + public void select(JTree tree, Object object, VirtualFile file) { if (object instanceof AbstractTreeNode) { AbstractTreeNode node = (AbstractTreeNode)object; @@ -193,20 +164,9 @@ class AsyncProjectViewSupport { LOG.debug("select AbstractTreeNode"); } if (object instanceof PsiElement) { - myAsyncTreeModel.visit(new ElementFinder((PsiElement)object)).done(path1 -> { - if (path1 != null) { - TreeUtil.selectPath(tree, path1); - } - else { - PsiElement element = PsiManager.getInstance(myProject).findFile(file); - if (element != null) { - myAsyncTreeModel.visit(new ElementFinder(element)).done(path2 -> { - if (path2 != null) { - TreeUtil.selectPath(tree, path2); - } - }); - } - } + selectElement(tree, (PsiElement)object, () -> { + PsiElement element = myPsiManager.findFile(file); + if (element != null) selectElement(tree, element, () -> LOG.debug("cannot find element")); }); } else { @@ -214,87 +174,37 @@ class AsyncProjectViewSupport { } } + private void selectElement(JTree tree, @NotNull PsiElement element, Runnable ifNotFound) { + myAsyncTreeModel.visit(new ProjectViewNodeVisitor(element)).done(path -> { + if (path != null) { + TreeUtil.selectPath(tree, path); + } + else if (ifNotFound != null) { + ifNotFound.run(); + } + }); + } + public void updateAll() { - if (myStructureTreeModel != null) { - myStructureTreeModel.invalidate(); - } + LOG.debug(new RuntimeException("reload a whole tree")); + myStructureTreeModel.invalidate(); + } + + public void update(@NotNull TreePath path) { + myStructureTreeModel.invalidate(path); + } + + public void update(@NotNull List list) { + for (TreePath path : list) update(path); } public void updateByFile(@NotNull VirtualFile file) { - if (myStructureTreeModel != null) { - myStructureTreeModel.invalidate(); //TODO: - } + PsiElement element = myPsiManager.findFile(file); + if (element != null) updateByElement(element); } public void updateByElement(@NotNull PsiElement element) { - if (myStructureTreeModel != null) { - myStructureTreeModel.invalidate(); //TODO: - } - } - - private static VirtualFile getVirtualFile(@NotNull PsiElement element) { - PsiFile file = element.getContainingFile(); - return file == null ? null : file.getVirtualFile(); - } - - /** - * @param object a node of a tree structure - * @param element an element to find - * @return {@code true} if the specified node represents the given element - */ - protected boolean found(Object object, @NotNull PsiElement element) { - if (object instanceof AbstractTreeNode) { - AbstractTreeNode node = (AbstractTreeNode)object; - return node.canRepresent(element); - } - LOG.debug("found unexpected object ", (object == null ? null : object.getClass())); - return false; - } - - /** - * @param object a node of a tree structure - * @param element an element to find - * @return {@code true} if the specified node is an ancestor of the given element - */ - protected boolean contains(Object object, @NotNull PsiElement element) { - VirtualFile file = getVirtualFile(element); - if (file == null) { - LOG.debug("no virtual file for element ", element); - } - else if (object instanceof ProjectViewNode) { - ProjectViewNode node = (ProjectViewNode)object; - if (node.contains(file)) return true; - } - if (object instanceof AbstractTreeNode) { - AbstractTreeNode node = (AbstractTreeNode)object; - Object value = node.getValue(); - return value instanceof PsiElement && PsiTreeUtil.isAncestor((PsiElement)value, element, true); - } - LOG.debug("contains unexpected object ", (object == null ? null : object.getClass())); - return false; - } - - private class ElementFinder implements TreeVisitor { - private final SmartPsiElementPointer pointer; - - private ElementFinder(@NotNull PsiElement element) { - pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(element); - } - - @NotNull - @Override - public Action accept(@NotNull TreePath path) { - LOG.debug("process ", path); - PsiElement element = pointer.getElement(); - if (element == null) return Action.SKIP_SIBLINGS; - Object component = path.getLastPathComponent(); - if (component instanceof DefaultMutableTreeNode) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode)component; - Object object = node.getUserObject(); - if (found(object, element)) return Action.INTERRUPT; - if (contains(object, element)) return Action.CONTINUE; - } - return Action.SKIP_CHILDREN; - } + SmartList list = new SmartList<>(); + myAsyncTreeModel.visit(new ProjectViewNodeVisitor(element, path -> !list.add(path)), false).done(path -> update(list)); } } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewNodeVisitor.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewNodeVisitor.java new file mode 100644 index 000000000000..5c13a09e9af9 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewNodeVisitor.java @@ -0,0 +1,71 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.projectView.impl; + +import com.intellij.ide.projectView.ProjectViewNode; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.SmartPointerManager; +import com.intellij.psi.SmartPsiElementPointer; +import com.intellij.ui.tree.AbstractTreeNodeVisitor; +import org.jetbrains.annotations.NotNull; + +import javax.swing.tree.TreePath; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; + +class ProjectViewNodeVisitor extends AbstractTreeNodeVisitor { + public ProjectViewNodeVisitor(@NotNull PsiElement element) { + super(create(element), (Predicate)null); + } + + public ProjectViewNodeVisitor(@NotNull PsiElement element, Predicate predicate) { + super(create(element), predicate); + } + + public ProjectViewNodeVisitor(@NotNull PsiElement element, Consumer consumer) { + super(create(element), consumer); + } + + @Override + protected boolean contains(@NotNull AbstractTreeNode node, @NotNull PsiElement element) { + return node instanceof ProjectViewNode && contains((ProjectViewNode)node, element) || super.contains(node, element); + } + + protected boolean contains(@NotNull ProjectViewNode node, @NotNull PsiElement element) { + PsiFile pf = element.getContainingFile(); + if (pf != null) { + VirtualFile vf = pf.getVirtualFile(); + if (vf != null) return node.contains(vf); + } + LOG.debug("no virtual file for element ", element); + return false; + } + + @Override + protected boolean isAncestor(Object value, @NotNull PsiElement element) { + return super.isAncestor(value, element); + } + + private static Supplier create(@NotNull PsiElement element) { + SmartPointerManager manager = SmartPointerManager.getInstance(element.getProject()); + SmartPsiElementPointer pointer = manager.createSmartPsiElementPointer(element); + return pointer::getElement; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/util/StructureViewCompositeModel.java b/platform/lang-impl/src/com/intellij/ide/util/StructureViewCompositeModel.java index 36cc762505a2..33aff66e0f2f 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/StructureViewCompositeModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/StructureViewCompositeModel.java @@ -26,11 +26,15 @@ import com.intellij.ide.util.treeView.smartTree.TreeElement; import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.Disposable; import com.intellij.psi.PsiFile; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; /** * @author Konstantin Bulenkov @@ -102,7 +106,7 @@ public class StructureViewCompositeModel extends StructureViewModelBase implemen final HashSet filters = new HashSet<>(); for (StructureViewComposite.StructureViewDescriptor view : myViews) { final StructureViewModel model = view.structureView.getTreeModel(); - filters.addAll(Arrays.asList(model.getFilters())); + ContainerUtil.addAll(filters, model.getFilters()); } return filters.toArray(new Filter[filters.size()]); } diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java index 3c59765009d7..1106b494178a 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java @@ -27,7 +27,6 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.impl.ActionManagerImpl; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; @@ -95,10 +94,9 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { private boolean processAbbreviations(final String pattern, Processor consumer, DataContext context) { List actionIds = AbbreviationManager.getInstance().findActions(pattern); JBIterable wrappers = JBIterable.from(actionIds) - .transform(myActionManager::getAction) - .filter(Condition.NOT_NULL) + .filterMap(myActionManager::getAction) .transform(action -> { - ActionWrapper wrapper = new ActionWrapper(action, myModel.myActionGroups.get(action), MatchMode.NAME, context); + ActionWrapper wrapper = new ActionWrapper(action, myModel.myActionGroups.get(action), MatchMode.NAME, context, myModel); return new MatchedValue(wrapper, pattern) { @NotNull @Override @@ -110,7 +108,7 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { return processItems(pattern, wrappers, consumer); } - private boolean processTopHits(String pattern, Processor consumer, DataContext dataContext) { + private static boolean processTopHits(String pattern, Processor consumer, DataContext dataContext) { Project project = CommonDataKeys.PROJECT.getData(dataContext); final CollectConsumer collector = new CollectConsumer<>(); for (SearchTopHitProvider provider : SearchTopHitProvider.EP_NAME.getExtensions()) { @@ -178,7 +176,7 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { for (OptionDescription description : optionDescriptions) { for (ActionFromOptionDescriptorProvider converter : ActionFromOptionDescriptorProvider.EP.getExtensions()) { AnAction action = converter.provide(description); - if (action != null) options.add(new ActionWrapper(action, null, MatchMode.NAME, dataContext)); + if (action != null) options.add(new ActionWrapper(action, null, MatchMode.NAME, dataContext, myModel)); options.add(description); } } @@ -188,7 +186,7 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { private boolean processActions(String pattern, Processor consumer, DataContext dataContext) { Set ids = ((ActionManagerImpl)myActionManager).getActionIds(); - JBIterable actions = JBIterable.from(ids).transform(myActionManager::getAction).filter(Condition.NOT_NULL); + JBIterable actions = JBIterable.from(ids).filterMap(myActionManager::getAction); MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); QuickActionProvider provider = dataContext.getData(QuickActionProvider.KEY); @@ -196,11 +194,11 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { actions = actions.append(provider.getActions(true)); } - JBIterable actionWrappers = actions.unique().transform(action -> { + JBIterable actionWrappers = actions.unique().filterMap(action -> { MatchMode mode = myModel.actionMatches(pattern, matcher, action); if (mode == MatchMode.NONE) return null; - return new ActionWrapper(action, myModel.myActionGroups.get(action), mode, dataContext); - }).filter(Condition.NOT_NULL); + return new ActionWrapper(action, myModel.myActionGroups.get(action), mode, dataContext, myModel); + }); return processItems(pattern, actionWrappers, consumer); } @@ -208,20 +206,16 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); Map intentionMap = myIntentions.getValue(); JBIterable intentions = JBIterable.from(intentionMap.keySet()) - .transform(intentionText -> { + .filterMap(intentionText -> { ApplyIntentionAction intentionAction = intentionMap.get(intentionText); if (myModel.actionMatches(pattern, matcher, intentionAction) == MatchMode.NONE) return null; - return new ActionWrapper(intentionAction, intentionText, MatchMode.INTENTION, dataContext); - }) - .filter(Condition.NOT_NULL); + return new ActionWrapper(intentionAction, intentionText, MatchMode.INTENTION, dataContext, myModel); + }); return processItems(pattern, intentions, consumer); } - private boolean processItems(String pattern, JBIterable items, Processor consumer) { - List itemList = items.toList(); - myModel.updateActions(ContainerUtil.findAll(itemList, ActionWrapper.class)); - - List matched = ContainerUtil.map(itemList, o -> o instanceof MatchedValue ? (MatchedValue)o : new MatchedValue(o, pattern)); + private static boolean processItems(String pattern, JBIterable items, Processor consumer) { + List matched = ContainerUtil.newArrayList(items.map(o -> o instanceof MatchedValue ? (MatchedValue)o : new MatchedValue(o, pattern))); Collections.sort(matched); return ContainerUtil.process(matched, consumer); } diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java index f2b2cbf8af14..0fb14d21f6cd 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java @@ -422,19 +422,17 @@ public class GotoActionModel implements ChooseByNameModel, Comparator, D return objects; } - void updateActions(List toUpdate) { - Semaphore semaphore = new Semaphore(toUpdate.size()); + private void updateOnEdt(Runnable update) { + Semaphore semaphore = new Semaphore(1); ProgressIndicator indicator = ProgressIndicatorProvider.getGlobalProgressIndicator(); - for (ActionWrapper wrapper : toUpdate) { - ApplicationManager.getApplication().invokeLater(() -> { - try { - wrapper.getPresentation(); - } - finally { - semaphore.up(); - } - }, myModality, __ -> indicator != null && indicator.isCanceled()); - } + ApplicationManager.getApplication().invokeLater(() -> { + try { + update.run(); + } + finally { + semaphore.up(); + } + }, myModality, __ -> indicator != null && indicator.isCanceled()); while (!semaphore.waitFor(10)) { if (indicator != null && indicator.isCanceled()) { @@ -463,13 +461,15 @@ public class GotoActionModel implements ChooseByNameModel, Comparator, D @NotNull private final MatchMode myMode; @Nullable private final String myGroupName; private final DataContext myDataContext; + private final GotoActionModel myModel; private volatile Presentation myPresentation; - public ActionWrapper(@NotNull AnAction action, @Nullable String groupName, @NotNull MatchMode mode, DataContext dataContext) { + public ActionWrapper(@NotNull AnAction action, @Nullable String groupName, @NotNull MatchMode mode, DataContext dataContext, GotoActionModel model) { myAction = action; myMode = mode; myGroupName = groupName; myDataContext = dataContext; + myModel = model; } @NotNull @@ -507,7 +507,14 @@ public class GotoActionModel implements ChooseByNameModel, Comparator, D public Presentation getPresentation() { if (myPresentation != null) return myPresentation; - return myPresentation = updateActionBeforeShow(myAction, myDataContext).getPresentation(); + Runnable r = () -> myPresentation = updateActionBeforeShow(myAction, myDataContext).getPresentation(); + if (ApplicationManager.getApplication().isDispatchThread()) { + r.run(); + } else { + myModel.updateOnEdt(r); + } + + return myPresentation; } private boolean hasPresentation() { diff --git a/platform/lang-impl/src/com/intellij/internal/ShowImageDuplicatesAction.java b/platform/lang-impl/src/com/intellij/internal/ShowImageDuplicatesAction.java index da172c7f9c5d..d67abb0dd1e8 100644 --- a/platform/lang-impl/src/com/intellij/internal/ShowImageDuplicatesAction.java +++ b/platform/lang-impl/src/com/intellij/internal/ShowImageDuplicatesAction.java @@ -18,6 +18,7 @@ package com.intellij.internal; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; @@ -40,7 +41,8 @@ public class ShowImageDuplicatesAction extends AnAction { public void actionPerformed(AnActionEvent e) { final Project project = getEventProject(e); assert project != null; - ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> collectAndShowDuplicates(project), "Gathering images", true, project); + ProgressManager.getInstance().runProcessWithProgressSynchronously( + () -> ReadAction.run(() -> collectAndShowDuplicates(project)), "Gathering images", true, project); } private static void collectAndShowDuplicates(final Project project) { diff --git a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/UniqueVFilePathBuilderImpl.java b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/UniqueVFilePathBuilderImpl.java index 5f410a7fc603..5217d69fcb14 100644 --- a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/UniqueVFilePathBuilderImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/UniqueVFilePathBuilderImpl.java @@ -64,15 +64,18 @@ public class UniqueVFilePathBuilderImpl extends UniqueVFilePathBuilder { return getUniqueVirtualFilePath(project, vFile, true, GlobalSearchScope.projectScope(project)); } - private static final Key>>>> + private static final Key>>>> ourShortNameBuilderCacheKey = Key.create("project's.short.file.name.builder"); private static final Key>>>> ourShortNameOpenedBuilderCacheKey = Key.create("project's.short.file.name.opened.builder"); private static final UniqueNameBuilder ourEmptyBuilder = new UniqueNameBuilder<>(null, null, -1); - private static String getUniqueVirtualFilePath(final Project project, VirtualFile file, final boolean skipNonOpenedFiles, GlobalSearchScope scope) { + private static String getUniqueVirtualFilePath(Project project, + VirtualFile file, + boolean skipNonOpenedFiles, + GlobalSearchScope scope) { Key>>>> key = - skipNonOpenedFiles ? ourShortNameOpenedBuilderCacheKey:ourShortNameBuilderCacheKey; + skipNonOpenedFiles ? ourShortNameOpenedBuilderCacheKey : ourShortNameBuilderCacheKey; CachedValue>>> data = project.getUserData(key); if (data == null) { project.putUserData(key, data = CachedValuesManager.getManager(project).createCachedValue( @@ -86,7 +89,7 @@ public class UniqueVFilePathBuilderImpl extends UniqueVFilePathBuilder { } ConcurrentMap>> scope2ValueMap = - (ConcurrentMap>>)data.getValue(); + (ConcurrentMap>>)data.getValue(); Map> valueMap = scope2ValueMap.get(scope); if (valueMap == null) { valueMap = ConcurrencyUtil.cacheOrGet(scope2ValueMap, scope, ContainerUtil.createConcurrentSoftValueMap()); @@ -96,22 +99,18 @@ public class UniqueVFilePathBuilderImpl extends UniqueVFilePathBuilder { UniqueNameBuilder uniqueNameBuilderForShortName = valueMap.get(fileName); if (uniqueNameBuilderForShortName == null) { - final UniqueNameBuilder builder = filesWithTheSameName( - fileName, - project, - skipNonOpenedFiles, - scope - ); - valueMap.put(fileName, builder != null ? builder:ourEmptyBuilder); + UniqueNameBuilder builder = filesWithTheSameName(fileName, project, skipNonOpenedFiles, scope); + valueMap.put(fileName, builder != null ? builder : ourEmptyBuilder); uniqueNameBuilderForShortName = builder; - } else if (uniqueNameBuilderForShortName == ourEmptyBuilder) { + } + else if (uniqueNameBuilderForShortName == ourEmptyBuilder) { uniqueNameBuilderForShortName = null; } if (uniqueNameBuilderForShortName != null && uniqueNameBuilderForShortName.contains(file)) { return uniqueNameBuilderForShortName.getShortPath(file); } - return file.getPresentableName(); + return file instanceof VirtualFilePathWrapper ? file.getPresentableName() : file.getName(); } @Nullable @@ -123,7 +122,7 @@ public class UniqueVFilePathBuilderImpl extends UniqueVFilePathBuilder { skipNonOpenedFiles ? Collections.emptySet() : FilenameIndex.getVirtualFilesByName(project, fileName, scope); THashSet setOfFilesWithTheSameName = new THashSet<>(filesWithSameName); // add open files out of project scope - for(VirtualFile openFile: FileEditorManager.getInstance(project).getOpenFiles()) { + for (VirtualFile openFile : FileEditorManager.getInstance(project).getOpenFiles()) { if (openFile.getName().equals(fileName)) { setOfFilesWithTheSameName.add(openFile); } @@ -142,7 +141,7 @@ public class UniqueVFilePathBuilderImpl extends UniqueVFilePathBuilder { String path = project.getBasePath(); path = path == null ? "" : FileUtil.toSystemIndependentName(path); UniqueNameBuilder builder = new UniqueNameBuilder<>(path, File.separator, 25); - for (VirtualFile virtualFile: filesWithSameName) { + for (VirtualFile virtualFile : filesWithSameName) { String presentablePath = virtualFile instanceof VirtualFilePathWrapper ? ((VirtualFilePathWrapper)virtualFile).getPresentablePath() : virtualFile.getPath(); builder.addPath(virtualFile, presentablePath); diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/DescendentBasedRootFilter.java b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/DescendentBasedRootFilter.java new file mode 100644 index 000000000000..0edb23f1763a --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/DescendentBasedRootFilter.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.roots.libraries.ui; + +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Predicate; + +/** + * Determines whether an archive or a directory can be used as a root of given type by analyzing its descending files; if there is at least one + * file under it satisfying the given condition, it assumes that the original archive/directory can be used as a root of the given type. + * + * @author nik + */ +public class DescendentBasedRootFilter extends RootFilter { + private final Predicate myCondition; + + public DescendentBasedRootFilter(OrderRootType rootType, boolean jarDirectory, String presentableRootTypeName, Predicate condition) { + super(rootType, jarDirectory, presentableRootTypeName); + myCondition = condition; + } + + /** + * @return filter which accepts file as a root if there is at least one file of {@code fileType} under it. + */ + public static DescendentBasedRootFilter createFileTypeBasedFilter(OrderRootType rootType, boolean jarDirectory, + @NotNull FileType fileType, String presentableRootTypeName) { + return new DescendentBasedRootFilter(rootType, jarDirectory, presentableRootTypeName, file -> fileType.equals(file.getFileType())); + } + + @Override + public boolean isAccepted(@NotNull VirtualFile rootCandidate, @NotNull final ProgressIndicator progressIndicator) { + if (isJarDirectory()) { + if (!rootCandidate.isDirectory() || !rootCandidate.isInLocalFileSystem()) { + return false; + } + for (VirtualFile child : rootCandidate.getChildren()) { + if (!child.isDirectory() && child.getFileType().equals(FileTypes.ARCHIVE)) { + final VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(child); + if (jarRoot != null && containsFileOfType(jarRoot, progressIndicator)) { + return true; + } + } + } + return false; + } + else { + return containsFileOfType(rootCandidate, progressIndicator); + } + } + + private boolean containsFileOfType(VirtualFile rootCandidate, final ProgressIndicator progressIndicator) { + return !VfsUtilCore.processFilesRecursively(rootCandidate, virtualFile -> { + progressIndicator.checkCanceled(); + if (virtualFile.isDirectory()) { + progressIndicator.setText2(virtualFile.getPath()); + return true; + } + return !myCondition.test(virtualFile); + }); + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/FileTypeBasedRootFilter.java b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/FileTypeBasedRootFilter.java index ad7ad88b460a..c0d77546e83a 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/FileTypeBasedRootFilter.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/FileTypeBasedRootFilter.java @@ -16,59 +16,30 @@ package com.intellij.openapi.roots.libraries.ui; import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.roots.OrderRootType; -import com.intellij.openapi.vfs.JarFileSystem; -import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; /** * Implementation of {@link RootDetector} which detects a root by presence of files of some specified type under it * * @author nik + * @deprecated use {@link DescendentBasedRootFilter#createFileTypeBasedFilter(OrderRootType, boolean, FileType, String)} instead */ public class FileTypeBasedRootFilter extends RootFilter { private final FileType myFileType; + private final RootFilter myDelegate; - public FileTypeBasedRootFilter(OrderRootType rootType, boolean jarDirectory, @NotNull FileType fileType, - final String presentableRootTypeName) { + public FileTypeBasedRootFilter(OrderRootType rootType, boolean jarDirectory, @NotNull FileType fileType, String presentableRootTypeName) { super(rootType, jarDirectory, presentableRootTypeName); myFileType = fileType; + myDelegate = new DescendentBasedRootFilter(rootType, jarDirectory, presentableRootTypeName, this::isFileAccepted); } @Override - public boolean isAccepted(@NotNull VirtualFile rootCandidate, @NotNull final ProgressIndicator progressIndicator) { - if (isJarDirectory()) { - if (!rootCandidate.isDirectory() || !rootCandidate.isInLocalFileSystem()) { - return false; - } - for (VirtualFile child : rootCandidate.getChildren()) { - if (!child.isDirectory() && child.getFileType().equals(FileTypes.ARCHIVE)) { - final VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(child); - if (jarRoot != null && containsFileOfType(jarRoot, progressIndicator)) { - return true; - } - } - } - return false; - } - else { - return containsFileOfType(rootCandidate, progressIndicator); - } - } - - private boolean containsFileOfType(VirtualFile rootCandidate, final ProgressIndicator progressIndicator) { - return !VfsUtil.processFilesRecursively(rootCandidate, virtualFile -> { - progressIndicator.checkCanceled(); - if (virtualFile.isDirectory()) { - progressIndicator.setText2(virtualFile.getPath()); - return true; - } - return !isFileAccepted(virtualFile); - }); + public boolean isAccepted(@NotNull VirtualFile rootCandidate, @NotNull ProgressIndicator progressIndicator) { + return myDelegate.isAccepted(rootCandidate, progressIndicator); } protected boolean isFileAccepted(VirtualFile virtualFile) { diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/RootDetector.java b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/RootDetector.java index 14aa9321f7bc..73de3dde1b58 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/RootDetector.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/RootDetector.java @@ -15,7 +15,6 @@ */ package com.intellij.openapi.roots.libraries.ui; -import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.vfs.VirtualFile; @@ -28,7 +27,7 @@ import java.util.Collection; * {@link LibraryRootsComponentDescriptor#getRootDetectors} method * * @see RootFilter - * @see FileTypeBasedRootFilter + * @see DescendentBasedRootFilter * @author nik */ public abstract class RootDetector { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java index d5806ef782dc..c09117302d15 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java @@ -53,7 +53,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; -public class PsiVFSListener implements VirtualFileListener { +public class PsiVFSListener implements VirtualFileListener, BulkFileListener { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.file.impl.PsiVFSListener"); private final FileTypeManager myFileTypeManager; @@ -75,8 +75,7 @@ public class PsiVFSListener implements VirtualFileListener { public void before(@NotNull List events) { for (Project project : ProjectManager.getInstance().getOpenProjects()) { PsiVFSListener listener = project.getComponent(PsiVFSListener.class); - assert listener != null; - new BulkVirtualFileListenerAdapter(listener).before(events); + listener.before(events); } } @@ -93,9 +92,8 @@ public class PsiVFSListener implements VirtualFileListener { } for (Project project : projects) { PsiVFSListener listener = project.getComponent(PsiVFSListener.class); - assert listener != null; listener.myReportedUnloadedPsiChange = false; - new BulkVirtualFileListenerAdapter(listener).after(events); + listener.after(events); listener.myReportedUnloadedPsiChange = false; } } @@ -141,37 +139,21 @@ public class PsiVFSListener implements VirtualFileListener { final VirtualFile vFile = event.getFile(); ApplicationManager.getApplication().runWriteAction( - new ExternalChangeAction() { - @Override - public void run() { - VirtualFile parent = vFile.getParent(); - PsiDirectory parentDir = getCachedDirectory(parent); - if (parentDir == null) { - // parent directory was never accessed via PSI - handleVfsChangeWithoutPsi(vFile); - return; - } - - if (!vFile.isDirectory()) { - PsiFile psiFile = myFileManager.findFile(vFile); - if (psiFile != null && psiFile.getProject() == myManager.getProject()) { - PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); - treeEvent.setParent(parentDir); - myManager.beforeChildAddition(treeEvent); - treeEvent.setChild(psiFile); - myManager.childAdded(treeEvent); - } - } - else { - PsiDirectory psiDir = myFileManager.findDirectory(vFile); - if (psiDir != null && psiDir.getProject() == myManager.getProject()) { - PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); - treeEvent.setParent(parentDir); - myManager.beforeChildAddition(treeEvent); - treeEvent.setChild(psiDir); - myManager.childAdded(treeEvent); - } - } + (ExternalChangeAction)() -> { + VirtualFile parent = vFile.getParent(); + PsiDirectory parentDir = getCachedDirectory(parent); + if (parentDir == null) { + // parent directory was never accessed via PSI + handleVfsChangeWithoutPsi(vFile); + return; + } + PsiFileSystemItem item = vFile.isDirectory() ? myFileManager.findDirectory(vFile) : myFileManager.findFile(vFile); + if (item != null && item.getProject() == myManager.getProject()) { + PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); + treeEvent.setParent(parentDir); + myManager.beforeChildAddition(treeEvent); + treeEvent.setChild(item); + myManager.childAdded(treeEvent); } } ); @@ -186,27 +168,13 @@ public class PsiVFSListener implements VirtualFileListener { if (parentDir == null) return; // do not notify listeners if parent directory was never accessed via PSI ApplicationManager.getApplication().runWriteAction( - new ExternalChangeAction() { - @Override - public void run() { - if (!vFile.isDirectory()) { - PsiFile psiFile = myFileManager.getCachedPsiFile(vFile); - if (psiFile != null) { - PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); - treeEvent.setParent(parentDir); - treeEvent.setChild(psiFile); - myManager.beforeChildRemoval(treeEvent); - } - } - else { - PsiDirectory psiDir = myFileManager.findDirectory(vFile); - if (psiDir != null) { - PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); - treeEvent.setParent(parentDir); - treeEvent.setChild(psiDir); - myManager.beforeChildRemoval(treeEvent); - } - } + (ExternalChangeAction)() -> { + PsiFileSystemItem item = vFile.isDirectory() ? myFileManager.findDirectory(vFile) : myFileManager.getCachedPsiFile(vFile); + if (item != null) { + PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); + treeEvent.setParent(parentDir); + treeEvent.setChild(item); + myManager.beforeChildRemoval(treeEvent); } } ); @@ -220,42 +188,32 @@ public class PsiVFSListener implements VirtualFileListener { final PsiDirectory parentDir = getCachedDirectory(parent); final PsiFile psiFile = myFileManager.getCachedPsiFileInner(vFile); + PsiElement element; if (psiFile != null) { clearViewProvider(vFile, "PSI fileDeleted"); - - if (parentDir != null) { - ApplicationManager.getApplication().runWriteAction(new ExternalChangeAction() { - @Override - public void run() { - PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); - treeEvent.setParent(parentDir); - treeEvent.setChild(psiFile); - myManager.childRemoved(treeEvent); - } - }); - } else if (parent != null) { - handleVfsChangeWithoutPsi(parent); - } + element = psiFile; } else { final PsiDirectory psiDir = myFileManager.getCachedDirectory(vFile); if (psiDir != null) { myFileManager.removeInvalidFilesAndDirs(false); - - if (parentDir != null) { - ApplicationManager.getApplication().runWriteAction(new ExternalChangeAction() { - @Override - public void run() { - PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); - treeEvent.setParent(parentDir); - treeEvent.setChild(psiDir); - myManager.childRemoved(treeEvent); - } - }); - } - } else if (parent != null) { - handleVfsChangeWithoutPsi(parent); + element = psiDir; } + else if (parent != null) { + handleVfsChangeWithoutPsi(parent); + return; + } + else { + element = null; + } + } + if (element != null && parentDir != null) { + ApplicationManager.getApplication().runWriteAction((ExternalChangeAction)() -> { + PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); + treeEvent.setParent(parentDir); + treeEvent.setChild(element); + myManager.childRemoved(treeEvent); + }); } } @@ -281,78 +239,75 @@ public class PsiVFSListener implements VirtualFileListener { if (parent != null && parentDir == null) return; // do not notifyListeners event if parent directory was never accessed via PSI ApplicationManager.getApplication().runWriteAction( - new ExternalChangeAction() { - @Override - public void run() { - PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); - treeEvent.setParent(parentDir); + (ExternalChangeAction)() -> { + PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); + treeEvent.setParent(parentDir); - if (VirtualFile.PROP_NAME.equals(propertyName)) { - final String newName = (String)event.getNewValue(); + if (VirtualFile.PROP_NAME.equals(propertyName)) { + final String newName = (String)event.getNewValue(); - if (parentDir == null) return; + if (parentDir == null) return; - if (vFile.isDirectory()) { - PsiDirectory psiDir = myFileManager.findDirectory(vFile); - if (psiDir != null) { - if (!myFileTypeManager.isFileIgnored(newName)) { - treeEvent.setChild(psiDir); - treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_DIRECTORY_NAME); - treeEvent.setOldValue(vFile.getName()); - treeEvent.setNewValue(newName); - myManager.beforePropertyChange(treeEvent); - } - else { - treeEvent.setChild(psiDir); - myManager.beforeChildRemoval(treeEvent); - } + if (vFile.isDirectory()) { + PsiDirectory psiDir = myFileManager.findDirectory(vFile); + if (psiDir != null) { + if (!myFileTypeManager.isFileIgnored(newName)) { + treeEvent.setChild(psiDir); + treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_DIRECTORY_NAME); + treeEvent.setOldValue(vFile.getName()); + treeEvent.setNewValue(newName); + myManager.beforePropertyChange(treeEvent); } else { - if ((!Registry.is("ide.hide.excluded.files") || !isExcludeRoot(vFile)) && !myFileTypeManager.isFileIgnored(newName)) { - myManager.beforeChildAddition(treeEvent); - } + treeEvent.setChild(psiDir); + myManager.beforeChildRemoval(treeEvent); } } else { - final FileViewProvider viewProvider = myFileManager.findViewProvider(vFile); - PsiFile psiFile = viewProvider.getPsi(viewProvider.getBaseLanguage()); - PsiFile psiFile1 = createFileCopyWithNewName(vFile, newName); - - if (psiFile != null) { - if (psiFile1 == null) { - treeEvent.setChild(psiFile); - myManager.beforeChildRemoval(treeEvent); - } - else if (!psiFile1.getClass().equals(psiFile.getClass())) { - treeEvent.setOldChild(psiFile); - myManager.beforeChildReplacement(treeEvent); - } - else { - treeEvent.setChild(psiFile); - treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_FILE_NAME); - treeEvent.setOldValue(vFile.getName()); - treeEvent.setNewValue(newName); - myManager.beforePropertyChange(treeEvent); - } - } - else { - if (psiFile1 != null) { - myManager.beforeChildAddition(treeEvent); - } + if ((!Registry.is("ide.hide.excluded.files") || !isExcludeRoot(vFile)) && !myFileTypeManager.isFileIgnored(newName)) { + myManager.beforeChildAddition(treeEvent); } } } - else if (VirtualFile.PROP_WRITABLE.equals(propertyName)) { - PsiFile psiFile = myFileManager.getCachedPsiFileInner(vFile); - if (psiFile == null) return; + else { + final FileViewProvider viewProvider1 = myFileManager.findViewProvider(vFile); + PsiFile psiFile = viewProvider1.getPsi(viewProvider1.getBaseLanguage()); + PsiFile psiFile1 = createFileCopyWithNewName(vFile, newName); - treeEvent.setElement(psiFile); - treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_WRITABLE); - treeEvent.setOldValue(event.getOldValue()); - treeEvent.setNewValue(event.getNewValue()); - myManager.beforePropertyChange(treeEvent); + if (psiFile != null) { + if (psiFile1 == null) { + treeEvent.setChild(psiFile); + myManager.beforeChildRemoval(treeEvent); + } + else if (!psiFile1.getClass().equals(psiFile.getClass())) { + treeEvent.setOldChild(psiFile); + myManager.beforeChildReplacement(treeEvent); + } + else { + treeEvent.setChild(psiFile); + treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_FILE_NAME); + treeEvent.setOldValue(vFile.getName()); + treeEvent.setNewValue(newName); + myManager.beforePropertyChange(treeEvent); + } + } + else { + if (psiFile1 != null) { + myManager.beforeChildAddition(treeEvent); + } + } } } + else if (VirtualFile.PROP_WRITABLE.equals(propertyName)) { + PsiFile psiFile = myFileManager.getCachedPsiFileInner(vFile); + if (psiFile == null) return; + + treeEvent.setElement(psiFile); + treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_WRITABLE); + treeEvent.setOldValue(event.getOldValue()); + treeEvent.setNewValue(event.getNewValue()); + myManager.beforePropertyChange(treeEvent); + } } ); } @@ -401,93 +356,90 @@ public class PsiVFSListener implements VirtualFileListener { } ApplicationManager.getApplication().runWriteAction( - new ExternalChangeAction() { - @Override - public void run() { - PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); - treeEvent.setParent(parentDir); + (ExternalChangeAction)() -> { + PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); + treeEvent.setParent(parentDir); - if (VirtualFile.PROP_NAME.equals(propertyName)) { - if (vFile.isDirectory()) { - PsiDirectory psiDir = myFileManager.getCachedDirectory(vFile); - if (psiDir != null) { - if (myFileTypeManager.isFileIgnored(vFile)) { - myFileManager.removeFilesAndDirsRecursively(vFile); + if (VirtualFile.PROP_NAME.equals(propertyName)) { + if (vFile.isDirectory()) { + PsiDirectory psiDir = myFileManager.getCachedDirectory(vFile); + if (psiDir != null) { + if (myFileTypeManager.isFileIgnored(vFile)) { + myFileManager.removeFilesAndDirsRecursively(vFile); - treeEvent.setChild(psiDir); - myManager.childRemoved(treeEvent); - } - else { - treeEvent.setElement(psiDir); - treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_DIRECTORY_NAME); - treeEvent.setOldValue(event.getOldValue()); - treeEvent.setNewValue(event.getNewValue()); - myManager.propertyChanged(treeEvent); - } + treeEvent.setChild(psiDir); + myManager.childRemoved(treeEvent); } else { - PsiDirectory psiDir1 = myFileManager.findDirectory(vFile); - if (psiDir1 != null) { - treeEvent.setChild(psiDir1); - myManager.childAdded(treeEvent); - } + treeEvent.setElement(psiDir); + treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_DIRECTORY_NAME); + treeEvent.setOldValue(event.getOldValue()); + treeEvent.setNewValue(event.getNewValue()); + myManager.propertyChanged(treeEvent); } } else { - final FileViewProvider fileViewProvider = myFileManager.createFileViewProvider(vFile, true); - final PsiFile newPsiFile = fileViewProvider.getPsi(fileViewProvider.getBaseLanguage()); - if(oldPsiFile != null) { - if (newPsiFile == null) { - clearViewProvider(vFile, "PSI renamed"); - - treeEvent.setChild(oldPsiFile); - myManager.childRemoved(treeEvent); - } - else if (!FileManagerImpl.areViewProvidersEquivalent(fileViewProvider, oldFileViewProvider)) { - myFileManager.setViewProvider(vFile, fileViewProvider); - - treeEvent.setOldChild(oldPsiFile); - treeEvent.setNewChild(newPsiFile); - myManager.childReplaced(treeEvent); - } - else { - FileManagerImpl.clearPsiCaches(oldFileViewProvider); - - treeEvent.setElement(oldPsiFile); - treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_FILE_NAME); - treeEvent.setOldValue(event.getOldValue()); - treeEvent.setNewValue(event.getNewValue()); - myManager.propertyChanged(treeEvent); - } - } - else if (newPsiFile != null) { - myFileManager.setViewProvider(vFile, fileViewProvider); - if (parentDir != null) { - treeEvent.setChild(newPsiFile); - myManager.childAdded(treeEvent); - } + PsiDirectory psiDir1 = myFileManager.findDirectory(vFile); + if (psiDir1 != null) { + treeEvent.setChild(psiDir1); + myManager.childAdded(treeEvent); } } } - else if (VirtualFile.PROP_WRITABLE.equals(propertyName)) { - if (oldPsiFile == null) return; + else { + final FileViewProvider fileViewProvider = myFileManager.createFileViewProvider(vFile, true); + final PsiFile newPsiFile = fileViewProvider.getPsi(fileViewProvider.getBaseLanguage()); + if(oldPsiFile != null) { + if (newPsiFile == null) { + clearViewProvider(vFile, "PSI renamed"); - treeEvent.setElement(oldPsiFile); - treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_WRITABLE); - treeEvent.setOldValue(event.getOldValue()); - treeEvent.setNewValue(event.getNewValue()); - myManager.propertyChanged(treeEvent); - } - else if (VirtualFile.PROP_ENCODING.equals(propertyName)) { - if (oldPsiFile == null) return; + treeEvent.setChild(oldPsiFile); + myManager.childRemoved(treeEvent); + } + else if (!FileManagerImpl.areViewProvidersEquivalent(fileViewProvider, oldFileViewProvider)) { + myFileManager.setViewProvider(vFile, fileViewProvider); - treeEvent.setElement(oldPsiFile); - treeEvent.setPropertyName(VirtualFile.PROP_ENCODING); - treeEvent.setOldValue(event.getOldValue()); - treeEvent.setNewValue(event.getNewValue()); - myManager.propertyChanged(treeEvent); + treeEvent.setOldChild(oldPsiFile); + treeEvent.setNewChild(newPsiFile); + myManager.childReplaced(treeEvent); + } + else { + FileManagerImpl.clearPsiCaches(oldFileViewProvider); + + treeEvent.setElement(oldPsiFile); + treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_FILE_NAME); + treeEvent.setOldValue(event.getOldValue()); + treeEvent.setNewValue(event.getNewValue()); + myManager.propertyChanged(treeEvent); + } + } + else if (newPsiFile != null) { + myFileManager.setViewProvider(vFile, fileViewProvider); + if (parentDir != null) { + treeEvent.setChild(newPsiFile); + myManager.childAdded(treeEvent); + } + } } } + else if (VirtualFile.PROP_WRITABLE.equals(propertyName)) { + if (oldPsiFile == null) return; + + treeEvent.setElement(oldPsiFile); + treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_WRITABLE); + treeEvent.setOldValue(event.getOldValue()); + treeEvent.setNewValue(event.getNewValue()); + myManager.propertyChanged(treeEvent); + } + else if (VirtualFile.PROP_ENCODING.equals(propertyName)) { + if (oldPsiFile == null) return; + + treeEvent.setElement(oldPsiFile); + treeEvent.setPropertyName(VirtualFile.PROP_ENCODING); + treeEvent.setOldValue(event.getOldValue()); + treeEvent.setNewValue(event.getNewValue()); + myManager.propertyChanged(treeEvent); + } } ); } @@ -502,46 +454,43 @@ public class PsiVFSListener implements VirtualFileListener { if (myFileTypeManager.isFileIgnored(vFile)) return; ApplicationManager.getApplication().runWriteAction( - new ExternalChangeAction() { - @Override - public void run() { - PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); + (ExternalChangeAction)() -> { + PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); - boolean isExcluded = vFile.isDirectory() && - Registry.is("ide.hide.excluded.files") && myProjectRootManager.getFileIndex().isExcluded(vFile); - if (oldParentDir != null && !isExcluded) { - if (newParentDir != null) { - treeEvent.setOldParent(oldParentDir); - treeEvent.setNewParent(newParentDir); - if (vFile.isDirectory()) { - PsiDirectory psiDir = myFileManager.findDirectory(vFile); - treeEvent.setChild(psiDir); - } - else { - PsiFile psiFile = myFileManager.findFile(vFile); - treeEvent.setChild(psiFile); - } - myManager.beforeChildMovement(treeEvent); + boolean isExcluded = vFile.isDirectory() && + Registry.is("ide.hide.excluded.files") && myProjectRootManager.getFileIndex().isExcluded(vFile); + if (oldParentDir != null && !isExcluded) { + if (newParentDir != null) { + treeEvent.setOldParent(oldParentDir); + treeEvent.setNewParent(newParentDir); + if (vFile.isDirectory()) { + PsiDirectory psiDir = myFileManager.findDirectory(vFile); + treeEvent.setChild(psiDir); } else { - treeEvent.setParent(oldParentDir); - if (vFile.isDirectory()) { - PsiDirectory psiDir = myFileManager.findDirectory(vFile); - treeEvent.setChild(psiDir); - } - else { - PsiFile psiFile = myFileManager.findFile(vFile); - treeEvent.setChild(psiFile); - } - myManager.beforeChildRemoval(treeEvent); + PsiFile psiFile = myFileManager.findFile(vFile); + treeEvent.setChild(psiFile); } + myManager.beforeChildMovement(treeEvent); } else { - LOG.assertTrue(newParentDir != null); // checked above - treeEvent.setParent(newParentDir); - myManager.beforeChildAddition(treeEvent); + treeEvent.setParent(oldParentDir); + if (vFile.isDirectory()) { + PsiDirectory psiDir = myFileManager.findDirectory(vFile); + treeEvent.setChild(psiDir); + } + else { + PsiFile psiFile = myFileManager.findFile(vFile); + treeEvent.setChild(psiFile); + } + myManager.beforeChildRemoval(treeEvent); } } + else { + LOG.assertTrue(newParentDir != null); // checked above + treeEvent.setParent(newParentDir); + myManager.beforeChildAddition(treeEvent); + } } ); } @@ -572,41 +521,38 @@ public class PsiVFSListener implements VirtualFileListener { if (oldElement == null && newElement == null) return; ApplicationManager.getApplication().runWriteAction( - new ExternalChangeAction() { - @Override - public void run() { - PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); - if (oldElement == null) { - myFileManager.setViewProvider(vFile, newViewProvider); - treeEvent.setParent(newParentDir); - treeEvent.setChild(newElement); - myManager.childAdded(treeEvent); + (ExternalChangeAction)() -> { + PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); + if (oldElement == null) { + myFileManager.setViewProvider(vFile, newViewProvider); + treeEvent.setParent(newParentDir); + treeEvent.setChild(newElement); + myManager.childAdded(treeEvent); + } + else { + if (newElement == null) { + clearViewProvider(vFile, "PSI moved"); + treeEvent.setParent(oldParentDir); + treeEvent.setChild(oldElement); + myManager.childRemoved(treeEvent); } else { - if (newElement == null) { - clearViewProvider(vFile, "PSI moved"); - treeEvent.setParent(oldParentDir); + if (newElement instanceof PsiDirectory || FileManagerImpl.areViewProvidersEquivalent(newViewProvider, ((PsiFile) oldElement).getViewProvider())) { + treeEvent.setOldParent(oldParentDir); + treeEvent.setNewParent(newParentDir); treeEvent.setChild(oldElement); - myManager.childRemoved(treeEvent); + myManager.childMoved(treeEvent); } else { - if (newElement instanceof PsiDirectory || FileManagerImpl.areViewProvidersEquivalent(newViewProvider, ((PsiFile) oldElement).getViewProvider())) { - treeEvent.setOldParent(oldParentDir); - treeEvent.setNewParent(newParentDir); - treeEvent.setChild(oldElement); - myManager.childMoved(treeEvent); - } - else { - myFileManager.setViewProvider(vFile, newViewProvider); - PsiTreeChangeEventImpl treeRemoveEvent = new PsiTreeChangeEventImpl(myManager); - treeRemoveEvent.setParent(oldParentDir); - treeRemoveEvent.setChild(oldElement); - myManager.childRemoved(treeRemoveEvent); - PsiTreeChangeEventImpl treeAddEvent = new PsiTreeChangeEventImpl(myManager); - treeAddEvent.setParent(newParentDir); - treeAddEvent.setChild(newElement); - myManager.childAdded(treeAddEvent); - } + myFileManager.setViewProvider(vFile, newViewProvider); + PsiTreeChangeEventImpl treeRemoveEvent = new PsiTreeChangeEventImpl(myManager); + treeRemoveEvent.setParent(oldParentDir); + treeRemoveEvent.setChild(oldElement); + myManager.childRemoved(treeRemoveEvent); + PsiTreeChangeEventImpl treeAddEvent = new PsiTreeChangeEventImpl(myManager); + treeAddEvent.setParent(newParentDir); + treeAddEvent.setChild(newElement); + myManager.childAdded(treeAddEvent); } } } @@ -629,26 +575,23 @@ public class PsiVFSListener implements VirtualFileListener { private class MyModuleRootListener implements ModuleRootListener { private VirtualFile[] myOldContentRoots; - private volatile int depthCounter; + private int depthCounter; // accessed from within write action only @Override public void beforeRootsChange(final ModuleRootEvent event) { if (!myFileManager.isInitialized()) return; if (event.isCausedByFileTypesChange()) return; ApplicationManager.getApplication().runWriteAction( - new ExternalChangeAction() { - @Override - public void run() { - depthCounter++; - if (depthCounter > 1) return; + (ExternalChangeAction)() -> { + depthCounter++; + if (depthCounter > 1) return; - PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); - treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_ROOTS); - final VirtualFile[] contentRoots = myProjectRootManager.getContentRoots(); - LOG.assertTrue(myOldContentRoots == null); - myOldContentRoots = contentRoots; - treeEvent.setOldValue(contentRoots); - myManager.beforePropertyChange(treeEvent); - } + PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); + treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_ROOTS); + final VirtualFile[] contentRoots = myProjectRootManager.getContentRoots(); + LOG.assertTrue(myOldContentRoots == null); + myOldContentRoots = contentRoots; + treeEvent.setOldValue(contentRoots); + myManager.beforePropertyChange(treeEvent); } ); } @@ -660,24 +603,21 @@ public class PsiVFSListener implements VirtualFileListener { if (!myFileManager.isInitialized()) return; if (event.isCausedByFileTypesChange()) return; ApplicationManager.getApplication().runWriteAction( - new ExternalChangeAction() { - @Override - public void run() { - depthCounter--; - assert depthCounter >= 0 : depthCounter; - if (depthCounter > 0) return; + (ExternalChangeAction)() -> { + depthCounter--; + assert depthCounter >= 0 : depthCounter; + if (depthCounter > 0) return; - myFileManager.removeInvalidFilesAndDirs(true); + myFileManager.removeInvalidFilesAndDirs(true); - PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); - treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_ROOTS); - final VirtualFile[] contentRoots = myProjectRootManager.getContentRoots(); - treeEvent.setNewValue(contentRoots); - LOG.assertTrue(myOldContentRoots != null); - treeEvent.setOldValue(myOldContentRoots); - myOldContentRoots = null; - myManager.propertyChanged(treeEvent); - } + PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); + treeEvent.setPropertyName(PsiTreeChangeEvent.PROP_ROOTS); + final VirtualFile[] contentRoots = myProjectRootManager.getContentRoots(); + treeEvent.setNewValue(contentRoots); + LOG.assertTrue(myOldContentRoots != null); + treeEvent.setOldValue(myOldContentRoots); + myOldContentRoots = null; + myManager.propertyChanged(treeEvent); } ); } @@ -689,14 +629,12 @@ public class PsiVFSListener implements VirtualFileListener { final PsiFile psiFile = myFileManager.getCachedPsiFileInner(file); if (psiFile != null) { ApplicationManager.getApplication().runWriteAction( - new ExternalChangeAction() { - @Override - public void run() { - if (FileDocumentManagerImpl.recomputeFileTypeIfNecessary(file)) { - myFileManager.forceReload(file); - } else { - myFileManager.reloadPsiAfterTextChange(psiFile, file); - } + (ExternalChangeAction)() -> { + if (FileDocumentManagerImpl.recomputeFileTypeIfNecessary(file)) { + myFileManager.forceReload(file); + } + else { + myFileManager.reloadPsiAfterTextChange(psiFile, file); } } ); @@ -709,12 +647,7 @@ public class PsiVFSListener implements VirtualFileListener { public void fileContentReloaded(@NotNull VirtualFile file, @NotNull Document document) { PsiFile psiFile = myFileManager.getCachedPsiFileInner(file); if (!file.isValid() || psiFile == null || !FileUtilRt.isTooLarge(file.getLength()) || psiFile instanceof PsiLargeFile) return; - ApplicationManager.getApplication().runWriteAction(new ExternalChangeAction() { - @Override - public void run() { - myFileManager.reloadPsiAfterTextChange(psiFile, file); - } - }); + ApplicationManager.getApplication().runWriteAction((ExternalChangeAction)() -> myFileManager.reloadPsiAfterTextChange(psiFile, file)); } } @@ -734,4 +667,18 @@ public class PsiVFSListener implements VirtualFileListener { ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(myProject); return index.isInContent(file) || index.isInLibraryClasses(file) || index.isInLibrarySource(file); } + + @Override + public void before(@NotNull List events) { + for (VFileEvent event : events) { + BulkVirtualFileListenerAdapter.fireBefore(this, event); + } + } + + @Override + public void after(@NotNull List events) { + for (VFileEvent event : events) { + BulkVirtualFileListenerAdapter.fireAfter(this, event); + } + } } diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/PrebuiltStubs.kt b/platform/lang-impl/src/com/intellij/psi/stubs/PrebuiltStubs.kt index f62877395c6d..aa7e8da07233 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/PrebuiltStubs.kt +++ b/platform/lang-impl/src/com/intellij/psi/stubs/PrebuiltStubs.kt @@ -17,15 +17,24 @@ package com.intellij.psi.stubs import com.google.common.hash.HashCode import com.google.common.hash.Hashing -import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.Disposable +import com.intellij.openapi.application.PathManager +import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.fileTypes.FileTypeExtension +import com.intellij.openapi.util.Disposer +import com.intellij.openapi.util.io.FileUtil import com.intellij.util.indexing.FileContent +import com.intellij.util.indexing.IndexInfrastructure import com.intellij.util.io.DataExternalizer import com.intellij.util.io.DataInputOutputUtil import com.intellij.util.io.KeyDescriptor +import com.intellij.util.io.PersistentHashMap import org.jetbrains.annotations.ApiStatus +import org.jetbrains.annotations.TestOnly import java.io.DataInput import java.io.DataOutput +import java.io.File +import java.io.IOException /** * @author traff @@ -33,9 +42,7 @@ import java.io.DataOutput val EP_NAME = "com.intellij.filetype.prebuiltStubsProvider" -object PrebuiltStubsProviders : FileTypeExtension(EP_NAME) { - val EXTENSION_POINT_NAME = ExtensionPointName.create(EP_NAME) -} +object PrebuiltStubsProviders : FileTypeExtension(EP_NAME) @ApiStatus.Experimental interface PrebuiltStubsProvider { @@ -45,16 +52,13 @@ interface PrebuiltStubsProvider { class FileContentHashing { private val hashing = Hashing.sha256() - fun hashString(fileContent: FileContent): HashCode { - return hashing.hashBytes(fileContent.content) - } + fun hashString(fileContent: FileContent) = hashing.hashBytes(fileContent.content) } class HashCodeDescriptor : HashCodeExternalizers(), KeyDescriptor { override fun getHashCode(value: HashCode): Int = value.hashCode() - override fun isEqual(val1: HashCode, val2: HashCode): Boolean = val1 == val2 companion object { @@ -83,4 +87,122 @@ class StubTreeExternalizer : DataExternalizer { } override fun read(`in`: DataInput) = SerializedStubTree(`in`) +} + +abstract class PrebuiltStubsProviderBase : PrebuiltStubsProvider, Disposable { + private val myFileContentHashing = FileContentHashing() + private var myPrebuiltStubsStorage: PersistentHashMap? = null + private var mySerializationManager: SerializationManagerImpl? = null + + protected abstract val stubVersion: Int + protected abstract val name: String + + init { + init() + } + + companion object { + val PREBUILT_INDICES_PATH_PROPERTY = "prebuilt_indices_path" + val SDK_STUBS_STORAGE_NAME = "sdk-stubs" + private val LOG = Logger.getInstance("#com.jetbrains.python.psi.impl.stubs.PyPrebuiltStubsProviderBase") + } + + internal fun init() { + var indexesRoot = findPrebuiltIndicesRoot() + try { + if (indexesRoot != null) { + // we should copy prebuilt indexes to a writable folder + indexesRoot = copyPrebuiltIndexesToIndexRoot(indexesRoot) + // otherwise we can get access denied error, because persistent hash map opens file for read and write + + val versionInFile = FileUtil.loadFile(File(indexesRoot, SDK_STUBS_STORAGE_NAME + ".version")) + + if (Integer.parseInt(versionInFile) == stubVersion) { + myPrebuiltStubsStorage = object : PersistentHashMap( + File(indexesRoot, SDK_STUBS_STORAGE_NAME + ".input"), + HashCodeDescriptor.instance, + StubTreeExternalizer()) { + override fun isReadOnly(): Boolean { + return true + } + } + + mySerializationManager = SerializationManagerImpl(File(indexesRoot, SDK_STUBS_STORAGE_NAME + ".names")) + + Disposer.register(this, mySerializationManager!!) + + LOG.info("Using prebuilt stubs from " + myPrebuiltStubsStorage!!.baseFile.absolutePath) + } + else { + LOG.error("Prebuilt stubs version mismatch: $versionInFile, current version is $versionInFile") + } + } + } + catch (e: Exception) { + myPrebuiltStubsStorage = null + LOG.warn("Prebuilt stubs can't be loaded at " + indexesRoot!!, e) + } + + } + + override fun findStub(fileContent: FileContent): Stub? { + if (myPrebuiltStubsStorage != null) { + val hashCode = myFileContentHashing.hashString(fileContent) + var stub: Stub? = null + try { + val stubTree = myPrebuiltStubsStorage!!.get(hashCode) + if (stubTree != null) { + stub = stubTree.getStub(false, mySerializationManager!!) + } + } + catch (e: SerializerNotFoundException) { + LOG.error("Can't deserialize stub tree", e) + } + catch (e: Exception) { + LOG.error("Error reading prebuilt stubs from " + myPrebuiltStubsStorage!!.baseFile.path, e) + myPrebuiltStubsStorage = null + stub = null + } + + if (stub != null) { + return stub + } + } + return null + } + + override fun dispose() { + if (myPrebuiltStubsStorage != null) { + try { + myPrebuiltStubsStorage!!.close() + } + catch (e: IOException) { + LOG.error(e) + } + } + } + + @Throws(IOException::class) + private fun copyPrebuiltIndexesToIndexRoot(prebuiltIndicesRoot: File): File { + val indexRoot = File(IndexInfrastructure.getPersistentIndexRoot(), "prebuilt/" + name) + + FileUtil.copyDir(prebuiltIndicesRoot, indexRoot) + + return indexRoot + } + + private fun findPrebuiltIndicesRoot(): File? { + var path: String? = System.getProperty(PREBUILT_INDICES_PATH_PROPERTY) + if (path != null && File(path).exists()) { + return File(path) + } + path = PathManager.getHomePath() + val f = File(path, "index/$name") // compiled binary + return if (f.exists()) f else null + } +} + +@TestOnly +fun PrebuiltStubsProviderBase.reset() { + this.init() } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java index eb0834ae735d..4462a4c98d5c 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java @@ -158,6 +158,6 @@ public class FileBasedIndexProjectHandler implements IndexableFileSet, Disposabl Collection files, final Project project, final FileBasedIndexImpl index) { - CacheUpdateRunner.processFiles(indicator, true, files, project, content -> index.processRefreshedFile(project, content)); + CacheUpdateRunner.processFiles(indicator, files, project, content -> index.processRefreshedFile(project, content)); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java index 7ce9f1e38c94..7ee3a2d38a76 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -106,7 +106,7 @@ public class UnindexedFilesUpdater extends DumbModeTask { } private void indexFiles(ProgressIndicator indicator, List files) { - CacheUpdateRunner.processFiles(indicator, true, files, myProject, content -> myIndex.indexFileContent(myProject, content)); + CacheUpdateRunner.processFiles(indicator, files, myProject, content -> myIndex.indexFileContent(myProject, content)); } @Override diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/DirectoryHistoryDialog.java b/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/DirectoryHistoryDialog.java index 859284d6d810..7f94bc29f1fb 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/DirectoryHistoryDialog.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/DirectoryHistoryDialog.java @@ -44,7 +44,6 @@ import javax.swing.event.DocumentEvent; import javax.swing.tree.DefaultTreeModel; import java.awt.*; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Set; @@ -128,18 +127,18 @@ public class DirectoryHistoryDialog extends HistoryDialog createChangesTree() { - return new ChangesTreeList(myProject, Collections.emptyList(), false, false, null, null) { + return new ChangesTreeList(myProject, false, false) { @Override protected DefaultTreeModel buildTreeModel(List cc, ChangeNodeDecorator changeNodeDecorator) { return TreeModelBuilder.buildFromChanges(myProject, isShowFlatten(), cc, changeNodeDecorator); } @Override - protected List getSelectedObjects(ChangesBrowserNode node) { + protected List getSelectedObjects(ChangesBrowserNode node) { return node.getAllChangesUnder(); } - protected Change getLeadSelectedObject(final ChangesBrowserNode node) { + protected Change getLeadSelectedObject(final ChangesBrowserNode node) { final Object o = node.getUserObject(); if (o instanceof Change) { return (Change)o; diff --git a/platform/platform-api/src/com/intellij/ide/browsers/chrome/ChromeSettings.java b/platform/platform-api/src/com/intellij/ide/browsers/chrome/ChromeSettings.java index bf6eba2845b6..4c46bba518b2 100644 --- a/platform/platform-api/src/com/intellij/ide/browsers/chrome/ChromeSettings.java +++ b/platform/platform-api/src/com/intellij/ide/browsers/chrome/ChromeSettings.java @@ -35,6 +35,7 @@ public final class ChromeSettings extends BrowserSpecificSettings { public static final String USER_DATA_DIR_ARG = "--user-data-dir="; public static final String NO_FIRST_RUN_ARG = "--no-first-run"; public static final String NO_DEFAULT_BROWSER_CHECK_ARG = "--no-default-browser-check"; + public static final String DISABLE_FIRST_RUN_EXPERIENCE_ARG = "--disable-fre"; private @Nullable String myCommandLineOptions; private @Nullable String myUserDataDirectoryPath; private boolean myUseCustomProfile; diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeBuilder.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeBuilder.java index d99b4915f168..2889bdf710d4 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeBuilder.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeBuilder.java @@ -198,7 +198,7 @@ public class AbstractTreeBuilder implements Disposable { * 2.Paths contain "model" element returned by getElement */ protected Object getTreeStructureElement(NodeDescriptor nodeDescriptor) { - return nodeDescriptor.getElement(); + return nodeDescriptor == null ? null : nodeDescriptor.getElement(); } diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java index 9dfe9a6dccf2..e3e386563b60 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java @@ -481,29 +481,25 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent Insets insets = super.getInsets(); Icon icon = getArrowIcon(isEnabled()); - boolean isEmpty = getIcon() == null && StringUtil.isEmpty(getText()); int x = size.width - icon.getIconWidth(); - if (isEmpty) { - x /= 2; - } else { - if (UIUtil.isUnderWin10LookAndFeel()) { - x -= JBUI.scale(6); - x -= JBUI.scale(UIUtil.getParentOfType(ActionToolbar.class, this) != null ? 2 : 0); - } else { - x -= insets.right; + if (UIUtil.isUnderWin10LookAndFeel()) { + x -= JBUI.scale(6); + x -= JBUI.scale(UIUtil.getParentOfType(ActionToolbar.class, this) != null ? 2 : 0); + } + else { + x -= insets.right; - if (isSmallVariant()) { - x += JBUI.scale(1); + if (isSmallVariant()) { + x += JBUI.scale(1); - if (UIUtil.isUnderDefaultMacTheme()) { - x -= JBUI.scale(3); - } - } - else { - x += JBUI.scale(UIUtil.isUnderNimbusLookAndFeel() ? -3 : 2); + if (UIUtil.isUnderDefaultMacTheme()) { + x -= JBUI.scale(3); } } + else { + x += JBUI.scale(UIUtil.isUnderNimbusLookAndFeel() ? -3 : 2); + } } icon.paintIcon(null, g, x, (size.height - icon.getIconHeight()) / 2); diff --git a/platform/platform-api/src/com/intellij/openapi/ui/ComboBox.java b/platform/platform-api/src/com/intellij/openapi/ui/ComboBox.java index 16e5fb1d2830..5031fec36c97 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/ComboBox.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/ComboBox.java @@ -252,7 +252,7 @@ public class ComboBox extends ComboBoxWithWidePopup implements AWTEventLis } @Override - public final Dimension getPreferredSize() { + public Dimension getPreferredSize() { int width = myMinimumAndPreferredWidth; final Dimension preferredSize = super.getPreferredSize(); if (width < 0) { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJComboBoxUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJComboBoxUI.java index 2a417c260710..8948a9420076 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJComboBoxUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJComboBoxUI.java @@ -52,7 +52,7 @@ public class WinIntelliJComboBoxUI extends DarculaComboBoxUI { private static final String HOVER_PROPERTY = "JComboBox.mouseHover"; private static final String PRESSED_PROPERTY = "JComboBox.mousePressed"; private static final Border DEFAULT_EDITOR_BORDER = JBUI.Borders.empty(1, 0); - private static final Dimension ARROW_BUTTON_SIZE = new JBDimension(21, 24); // Count borders + private static final JBDimension ARROW_BUTTON_SIZE = new JBDimension(21, 24); // Count borders private MouseListener mouseListener; @@ -225,6 +225,9 @@ public class WinIntelliJComboBoxUI extends DarculaComboBoxUI { Rectangle innerRect = new Rectangle(getSize()); JBInsets.removeFrom(innerRect, getInsets()); + int bw = comboBox.getClientProperty("JComponent.error.outline") == Boolean.TRUE ? 2 : 1; // see paintBorder() + JBInsets.removeFrom(innerRect, JBUI.insets(bw)); + // paint background if (comboBox.isEditable() && comboBox.isEnabled()) { if (isPressed() || popup.isVisible()) { @@ -508,6 +511,7 @@ public class WinIntelliJComboBoxUI extends DarculaComboBoxUI { } private Dimension getSizeWithButton(Dimension d) { + ARROW_BUTTON_SIZE.update(); Insets i = comboBox.getInsets(); int width = ARROW_BUTTON_SIZE.width + i.left; return new Dimension(Math.max(d.width + JBUI.scale(10), width), diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/beans/ConvertUsagesUtil.java b/platform/platform-impl/src/com/intellij/internal/statistic/beans/ConvertUsagesUtil.java index 9944040c8afc..4e3854660517 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/beans/ConvertUsagesUtil.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/beans/ConvertUsagesUtil.java @@ -165,7 +165,7 @@ public class ConvertUsagesUtil { */ @NotNull public static String escapeDescriptorName(@NotNull final String name) { - return name.replace(" ", "_"). + return name. replace(GROUP_SEPARATOR, '_'). replace(GROUPS_SEPARATOR, '_'). replace(GROUP_VALUE_SEPARATOR, '_') diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/customUsageCollectors/actions/MainMenuCollector.java b/platform/platform-impl/src/com/intellij/internal/statistic/customUsageCollectors/actions/MainMenuCollector.java new file mode 100644 index 000000000000..a3796f0b24a2 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/internal/statistic/customUsageCollectors/actions/MainMenuCollector.java @@ -0,0 +1,141 @@ +/* + * Copyright 2000-2017 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.internal.statistic.customUsageCollectors.actions; + +import com.intellij.internal.statistic.UsagesCollector; +import com.intellij.internal.statistic.beans.ConvertUsagesUtil; +import com.intellij.internal.statistic.beans.GroupDescriptor; +import com.intellij.internal.statistic.beans.UsageDescriptor; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.impl.ActionMenu; +import com.intellij.openapi.components.*; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.xmlb.annotations.MapAnnotation; +import com.intellij.util.xmlb.annotations.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ItemEvent; +import java.awt.event.MouseEvent; +import java.util.*; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Konstantin Bulenkov + */ +@State( + name = "MainMenuCollector", + storages = @Storage(value = "statistics.main_menu.xml", roamingType = RoamingType.DISABLED) +) +public class MainMenuCollector implements PersistentStateComponent { + private State myState = new State(); + @Nullable + @Override + public State getState() { + return myState; + } + + @Override + public void loadState(State state) { + myState = state; + } + + public void record(@NotNull AnAction action) { + try { + AWTEvent e = EventQueue.getCurrentEvent(); + String path = null; + if (e instanceof ItemEvent) { + path = getPathFromMenuItem(e, action); + } + else if (e instanceof MouseEvent) { + path = getPathFromMenuSelectionManager(action); + } + + if (!StringUtil.isEmpty(path)) { + String key = ConvertUsagesUtil.escapeDescriptorName(path); + final Integer count = myState.myValues.get(key); + int value = count == null ? 1 : count + 1; + myState.myValues.put(key, value); + } + } + catch (Exception ignore) { + } + } + + protected String getPathFromMenuSelectionManager(@NotNull AnAction action) { + List groups = Arrays.stream(MenuSelectionManager.defaultManager().getSelectedPath()) + .filter(o -> o instanceof ActionMenu) + .map(o -> ((ActionMenu)o).getText()) + .collect(Collectors.toList()); + if (groups.size() > 0) { + String text = action.getTemplatePresentation().getText(); //avoid user data in Action Presentation + groups.add(text); + return convertMenuItemsToKey(groups); + } + return null; + } + + @NotNull + private static String convertMenuItemsToKey(List menuItems) { + return StringUtil.join(menuItems, " -> "); + } + + @NotNull + protected String getPathFromMenuItem(AWTEvent e, AnAction action) { + Object src = e.getSource(); + ArrayList items = new ArrayList<>(); + while (src instanceof MenuItem) { + items.add (0, ((MenuItem)src).getLabel()); + src = ((MenuItem)src).getParent(); + } + if (items.size() > 1) { + items.set(items.size() - 1, action.getTemplatePresentation().getText()); //avoid user data in Action Presentation + } + return convertMenuItemsToKey(items); + } + + + public static MainMenuCollector getInstance() { + return ServiceManager.getService(MainMenuCollector.class); + } + + + final static class State { + @Tag("counts") + @MapAnnotation(surroundWithTag = false, keyAttributeName = "path", valueAttributeName = "count") + public Map myValues = new HashMap<>(); + } + + final static class MainMenuUsagesCollector extends UsagesCollector { + private static final GroupDescriptor GROUP = GroupDescriptor.create("Main Menu", GroupDescriptor.HIGHER_PRIORITY); + + @NotNull + public Set getUsages() { + State state = getInstance().getState(); + assert state != null; + return ContainerUtil.map2Set(state.myValues.entrySet(), e -> new UsageDescriptor(e.getKey(), e.getValue())); + } + + @NotNull + public GroupDescriptor getGroupId() { + return GROUP; + } + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java index 8f51c4230607..88a187cc416f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java @@ -226,6 +226,7 @@ public class ActionButton extends JComponent implements ActionButtonComponent, A } @Override public Dimension getPreferredSize() { + if (myMinimumButtonSize != null) myMinimumButtonSize.update(); Icon icon = getIcon(); if (icon.getIconWidth() < myMinimumButtonSize.width && icon.getIconHeight() < myMinimumButtonSize.height) { diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenuItem.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenuItem.java index ebb1ac214a76..8acc00e30b7a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenuItem.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenuItem.java @@ -17,6 +17,7 @@ package com.intellij.openapi.actionSystem.impl; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.ui.UISettings; +import com.intellij.internal.statistic.customUsageCollectors.actions.MainMenuCollector; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; @@ -100,6 +101,14 @@ public class ActionMenuItem extends JBCheckBoxMenuItem { } } + public AnAction getAnAction() { + return myAction.getAction(); + } + + public String getPlace() { + return myPlace; + } + private static boolean isEnterKeyStroke(KeyStroke keyStroke) { return keyStroke.getKeyCode() == KeyEvent.VK_ENTER && keyStroke.getModifiers() == 0; } @@ -114,6 +123,10 @@ public class ActionMenuItem extends JBCheckBoxMenuItem { */ @Override public void fireActionPerformed(ActionEvent event) { + AnAction action = myAction.getAction(); + if (action != null && ActionPlaces.MAIN_MENU.equals(myPlace)) { + MainMenuCollector.getInstance().record(action); + } TransactionGuard.submitTransaction(ApplicationManager.getApplication(), () -> super.fireActionPerformed(event)); } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java index e21b48ebb510..773181465882 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java @@ -94,7 +94,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar, QuickAct */ private final List myComponentBounds = new ArrayList<>(); - private Dimension myMinimumButtonSize = JBUI.emptySize(); + private JBDimension myMinimumButtonSize = JBUI.emptySize(); /** * @see ActionToolbar#getLayoutPolicy() @@ -825,6 +825,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar, QuickAct @Override public Dimension getPreferredSize() { final ArrayList bounds = new ArrayList<>(); + if (myMinimumButtonSize != null) myMinimumButtonSize.update(); calculateBounds(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE), bounds); if (bounds.isEmpty()) return JBUI.emptySize(); int xLeft = Integer.MAX_VALUE; @@ -899,7 +900,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar, QuickAct } private final class MySeparator extends JComponent { - private final Dimension mySize; + private final JBDimension mySize; public MySeparator() { if (myOrientation == SwingConstants.HORIZONTAL) { @@ -912,6 +913,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar, QuickAct @Override public Dimension getPreferredSize() { + mySize.update(); return mySize; } @@ -957,7 +959,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar, QuickAct @Override public void setMinimumButtonSize(@NotNull final Dimension size) { - myMinimumButtonSize = size; + myMinimumButtonSize = JBDimension.create(size, false); for (int i = getComponentCount() - 1; i >= 0; i--) { final Component component = getComponent(i); if (component instanceof ActionButton) { diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ReadMostlyRWLock.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ReadMostlyRWLock.java index 7957069f212f..712299a20755 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ReadMostlyRWLock.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ReadMostlyRWLock.java @@ -21,6 +21,7 @@ import com.intellij.openapi.application.ex.ApplicationUtil; import com.intellij.openapi.diagnostic.Attachment; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.impl.CoreProgressManager; import com.intellij.util.containers.ConcurrentList; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -122,7 +123,7 @@ class ReadMostlyRWLock { private void throwIfImpatient(Reader status) { // when client explicitly runs in non-cancelable block do not throw from within nested read actions - if (status.impatientReads && writeRequested && !ProgressManager.getInstance().isInNonCancelableSection()) { + if (status.impatientReads && writeRequested && !ProgressManager.getInstance().isInNonCancelableSection() && CoreProgressManager.ENABLED) { throw new ApplicationUtil.CannotRunReadActionException(); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java index a47e25a69b99..d293573dbf45 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java @@ -196,7 +196,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis Set providers = new HashSet<>(); List composites = getEditorComposites(file); for (EditorWithProviderComposite composite : composites) { - providers.addAll(Arrays.asList(composite.getProviders())); + ContainerUtil.addAll(providers, composite.getProviders()); } FileEditorProvider[] newProviders = FileEditorProviderManager.getInstance().getProviders(project, file); if (newProviders.length > providers.size()) { @@ -485,7 +485,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis Set all = getAllSplitters(); for (EditorsSplitters each : all) { EditorWindow[] eachList = each.getWindows(); - windows.addAll(Arrays.asList(eachList)); + ContainerUtil.addAll(windows, eachList); } return windows.toArray(new EditorWindow[windows.size()]); @@ -1216,7 +1216,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis public VirtualFile[] getOpenFiles() { Set openFiles = new THashSet<>(); for (EditorsSplitters each : getAllSplitters()) { - openFiles.addAll(Arrays.asList(each.getOpenFiles())); + ContainerUtil.addAll(openFiles, each.getOpenFiles()); } return VfsUtilCore.toVirtualFileArray(openFiles); } @@ -1226,10 +1226,10 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis public VirtualFile[] getSelectedFiles() { Set selectedFiles = new LinkedHashSet<>(); EditorsSplitters activeSplitters = getSplitters(); - selectedFiles.addAll(Arrays.asList(activeSplitters.getSelectedFiles())); + ContainerUtil.addAll(selectedFiles, activeSplitters.getSelectedFiles()); for (EditorsSplitters each : getAllSplitters()) { if (each != activeSplitters) { - selectedFiles.addAll(Arrays.asList(each.getSelectedFiles())); + ContainerUtil.addAll(selectedFiles, each.getSelectedFiles()); } } return VfsUtilCore.toVirtualFileArray(selectedFiles); @@ -1240,7 +1240,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis public FileEditor[] getSelectedEditors() { Set selectedEditors = new HashSet<>(); for (EditorsSplitters each : getAllSplitters()) { - selectedEditors.addAll(Arrays.asList(each.getSelectedEditors())); + ContainerUtil.addAll(selectedEditors, each.getSelectedEditors()); } return selectedEditors.toArray(new FileEditor[selectedEditors.size()]); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/PlatformFileTypeFactory.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/PlatformFileTypeFactory.java index a84a0d452b84..5fc1ec7ce173 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/PlatformFileTypeFactory.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/PlatformFileTypeFactory.java @@ -25,7 +25,7 @@ import org.jetbrains.annotations.NotNull; public class PlatformFileTypeFactory extends FileTypeFactory { public void createFileTypes(@NotNull final FileTypeConsumer consumer) { consumer.consume(ArchiveFileType.INSTANCE, "zip;jar;war;ear;swc;ane;egg;apk"); - consumer.consume(PlainTextFileType.INSTANCE, "txt;sh;bat;cmd;policy;log;cgi;MF;jad;jam;htaccess;rb"); + consumer.consume(PlainTextFileType.INSTANCE, "txt;sh;bat;cmd;policy;log;cgi;MF;jad;jam;htaccess;rb;opts"); consumer.consume(NativeFileType.INSTANCE, "doc;docx;xls;xlsx;ppt;pptx;mdb;vsd;pdf;hlp;chm;odt"); consumer.consume(UnknownFileType.INSTANCE, "lib;dll;a;so;dylib"); } diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/util/BackgroundTaskUtil.java b/platform/platform-impl/src/com/intellij/openapi/progress/util/BackgroundTaskUtil.java index 06aaae5eb63d..0e41d05f596d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/progress/util/BackgroundTaskUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/progress/util/BackgroundTaskUtil.java @@ -32,6 +32,7 @@ import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Pair; import com.intellij.util.Consumer; import com.intellij.util.Function; +import com.intellij.util.IncorrectOperationException; import com.intellij.util.PairConsumer; import com.intellij.util.concurrency.AppExecutorUtil; import com.intellij.util.messages.MessageBus; @@ -47,6 +48,27 @@ import java.util.concurrent.atomic.AtomicReference; public class BackgroundTaskUtil { private static final Logger LOG = Logger.getInstance(BackgroundTaskUtil.class); + /** + * Executor to perform possibly long operation on pooled thread. + * If computation was performed within given time frame, + * the computed callback will be executed synchronously (avoiding unnecessary invokeLater()). + * In this case, {@code onSlowAction} will not be executed at all. + *
    + *
  • If the computation is fast, execute callback synchronously. + *
  • If the computation is slow, execute onSlowAction synchronously. When the computation is completed, execute callback in EDT. + *

+ * It can be used to reduce blinking when background task might be completed fast.
+ * A Simple approach: + *

+    * onSlowAction.run() // show "Loading..."
+    * executeOnPooledThread({
+    *   Runnable callback = backgroundTask(); // some background computations
+    *   invokeLater(callback); // apply changes
+    * });
+    * 
+ * will lead to "Loading..." visible between current moment and execution of invokeLater() event. + * This period can be very short and looks like 'jumping' if background operation is fast. + */ @NotNull @CalledInAwt public static ProgressIndicator executeAndTryWait(@NotNull Function backgroundTask, @@ -194,7 +216,14 @@ public class BackgroundTaskUtil { boolean onPooledThread) { ProgressIndicator indicator = new EmptyProgressIndicator(modalityState); indicator.start(); - Runnable toRun = () -> ProgressManager.getInstance().runProcess(task, indicator); + Runnable toRun = () -> { + try { + ProgressManager.getInstance().runProcess(task, indicator); + } + catch (ProcessCanceledException pce) { + // ignore: expected cancellation + } + }; if (onPooledThread) { CompletableFuture future = CompletableFuture.runAsync(toRun, AppExecutorUtil.getAppExecutorService()); @@ -208,14 +237,22 @@ public class BackgroundTaskUtil { } }; - Disposer.register(parent, disposable); + if (!registerIfParentNotDisposed(parent, disposable)) { + indicator.cancel(); + return indicator; + } future.whenComplete((o, e) -> Disposer.dispose(disposable)); } else { Disposable disposable = () -> { if (indicator.isRunning()) indicator.cancel(); }; - Disposer.register(parent, disposable); + + if (!registerIfParentNotDisposed(parent, disposable)) { + indicator.cancel(); + return indicator; + } + try { toRun.run(); } @@ -226,6 +263,20 @@ public class BackgroundTaskUtil { return indicator; } + private static boolean registerIfParentNotDisposed(@NotNull Disposable parent, @NotNull Disposable disposable) { + return ReadAction.compute(() -> { + if (Disposer.isDisposed(parent)) return false; + try { + Disposer.register(parent, disposable); + return true; + } + catch(IncorrectOperationException ioe) { + LOG.error(ioe); + return false; + } + }); + } + @CalledInAny public static void runUnderDisposeAwareIndicator(@NotNull Disposable parent, @NotNull Runnable task) { runUnderDisposeAwareIndicator(task, parent, ModalityState.defaultModalityState(), false); @@ -235,6 +286,8 @@ public class BackgroundTaskUtil { * Wraps {@link MessageBus#syncPublisher(Topic)} in a dispose check, * and throws a {@link ProcessCanceledException} if the project is disposed, * instead of throwing an assertion which would happen otherwise. + * + * @see #syncPublisher(Topic) */ @CalledInAny @NotNull diff --git a/platform/platform-impl/src/com/intellij/openapi/project/CacheUpdateRunner.java b/platform/platform-impl/src/com/intellij/openapi/project/CacheUpdateRunner.java index 3343c9cd206a..634dbe5fc9d7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/CacheUpdateRunner.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/CacheUpdateRunner.java @@ -46,10 +46,7 @@ public class CacheUpdateRunner { private static final int PROC_COUNT = Runtime.getRuntime().availableProcessors(); public static final int DEFAULT_MAX_INDEXER_THREADS = 4; - public static void processFiles(final ProgressIndicator indicator, - boolean processInReadAction, - Collection files, - Project project, Consumer processor) { + public static void processFiles(ProgressIndicator indicator, Collection files, Project project, Consumer processor) { indicator.checkCanceled(); final FileContentQueue queue = new FileContentQueue(files, indicator); final double total = files.size(); @@ -85,8 +82,7 @@ public class CacheUpdateRunner { while (!project.isDisposed()) { indicator.checkCanceled(); - // todo wait for the user... - if (processSomeFilesWhileUserIsInactive(queue, progressUpdater, processInReadAction, project, processor)) { + if (processSomeFilesWhileUserIsInactive(queue, progressUpdater, indicator, project, processor)) { break; } } @@ -104,7 +100,7 @@ public class CacheUpdateRunner { private static boolean processSomeFilesWhileUserIsInactive(@NotNull FileContentQueue queue, @NotNull ProgressUpdater progressUpdater, - final boolean processInReadAction, + @NotNull ProgressIndicator suspendableIndicator, @NotNull Project project, @NotNull Consumer fileProcessor) { final ProgressIndicatorBase innerIndicator = new ProgressIndicatorBase() { @@ -126,7 +122,7 @@ public class CacheUpdateRunner { try { int threadsCount = indexingThreadCount(); if (threadsCount == 1 || application.isWriteAccessAllowed()) { - Runnable process = new MyRunnable(innerIndicator, queue, isFinished, progressUpdater, processInReadAction, project, fileProcessor); + Runnable process = new MyRunnable(innerIndicator, suspendableIndicator, queue, isFinished, progressUpdater, project, fileProcessor); ProgressManager.getInstance().runProcess(process, innerIndicator); } else { @@ -135,7 +131,7 @@ public class CacheUpdateRunner { for (int i = 0; i < threadsCount; i++) { AtomicBoolean ref = new AtomicBoolean(); finishedRefs[i] = ref; - Runnable process = new MyRunnable(innerIndicator, queue, ref, progressUpdater, processInReadAction, project, fileProcessor); + Runnable process = new MyRunnable(innerIndicator, suspendableIndicator, queue, ref, progressUpdater, project, fileProcessor); futures[i] = application.executeOnPooledThread(process); } isFinished.set(waitForAll(finishedRefs, futures)); @@ -183,25 +179,25 @@ public class CacheUpdateRunner { private static class MyRunnable implements Runnable { private final ProgressIndicatorBase myInnerIndicator; + private final ProgressIndicator mySuspendableIndicator; private final FileContentQueue myQueue; private final AtomicBoolean myFinished; private final ProgressUpdater myProgressUpdater; - private final boolean myProcessInReadAction; @NotNull private final Project myProject; @NotNull private final Consumer myProcessor; - public MyRunnable(@NotNull ProgressIndicatorBase innerIndicator, - @NotNull FileContentQueue queue, - @NotNull AtomicBoolean finished, - @NotNull ProgressUpdater progressUpdater, - boolean processInReadAction, - @NotNull Project project, - @NotNull Consumer fileProcessor) { + MyRunnable(@NotNull ProgressIndicatorBase innerIndicator, + @NotNull ProgressIndicator suspendableIndicator, + @NotNull FileContentQueue queue, + @NotNull AtomicBoolean finished, + @NotNull ProgressUpdater progressUpdater, + @NotNull Project project, + @NotNull Consumer fileProcessor) { myInnerIndicator = innerIndicator; + mySuspendableIndicator = suspendableIndicator; myQueue = queue; myFinished = finished; myProgressUpdater = progressUpdater; - myProcessInReadAction = processInReadAction; myProject = project; myProcessor = fileProcessor; } @@ -213,6 +209,8 @@ public class CacheUpdateRunner { return; } try { + mySuspendableIndicator.checkCanceled(); + final FileContent fileContent = myQueue.take(myInnerIndicator); if (fileContent == null) { myFinished.set(true); @@ -241,14 +239,9 @@ public class CacheUpdateRunner { try { ProgressManager.getInstance().runProcess( () -> { - if (myProcessInReadAction) { - // in wait methods we don't want to deadlock by grabbing write lock (or having it in queue) and trying to run read action in separate thread - if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(action)) { - throw new ProcessCanceledException(); - } - } - else { - action.run(); + // in wait methods we don't want to deadlock by grabbing write lock (or having it in queue) and trying to run read action in separate thread + if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(action)) { + throw new ProcessCanceledException(); } }, ProgressWrapper.wrap(myInnerIndicator) diff --git a/platform/platform-impl/src/com/intellij/openapi/project/FileContentQueue.java b/platform/platform-impl/src/com/intellij/openapi/project/FileContentQueue.java index ca6ac5a8bb44..38bcfc443406 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/FileContentQueue.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/FileContentQueue.java @@ -101,7 +101,11 @@ public class FileContentQueue { private PreloadState preloadNextContent() { try { if (myLoadedBytesInQueue.get() > MAX_SIZE_OF_BYTES_IN_QUEUE) { - synchronized (ourProceedWithLoadingLock) { ourProceedWithLoadingLock.wait(300); } + // wait a little for indexer threads to consume content, they will awake us earlier once we can proceed + synchronized (ourProceedWithLoadingLock) { + //noinspection WaitNotInLoop + ourProceedWithLoadingLock.wait(300); + } myProgressIndicator.checkCanceled(); return PreloadState.TOO_MUCH_DATA_PRELOADED; } @@ -226,6 +230,7 @@ public class FileContentQueue { long loadedBytesInQueueNow = myLoadedBytesInQueue.addAndGet(-result.getLength()); if (loadedBytesInQueueNow < MAX_SIZE_OF_BYTES_IN_QUEUE) { + // nudge content preloader to proceed synchronized (ourProceedWithLoadingLock) { // we actually ask only content loading thread to proceed, so there should not be much difference with plain notify ourProceedWithLoadingLock.notifyAll(); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/DummyCachingFileSystem.java b/platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/DummyCachingFileSystem.java index 33de7529e278..4cbcb4547cb6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/DummyCachingFileSystem.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/DummyCachingFileSystem.java @@ -123,7 +123,10 @@ public abstract class DummyCachingFileSystem extends Dumm @NotNull public Collection getCachedFiles() { - return myCachedFiles.values().stream().filter(Objects::nonNull).collect(Collectors.toList()); + return myCachedFiles.values().stream() + .filter(Objects::nonNull) + .filter(VirtualFile::isValid) + .collect(Collectors.toList()); } public void onProjectClosed() { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java index 2e5506677418..edec81f4021a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vfs.impl; +import com.intellij.concurrency.ConcurrentCollectionFactory; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -35,7 +36,6 @@ import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener; import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.SmartList; -import com.intellij.concurrency.ConcurrentCollectionFactory; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.URLUtil; import com.intellij.util.messages.MessageBus; @@ -312,33 +312,8 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp } } - private final Set myStoredPointers = ContainerUtil.newIdentityTroveSet(); - @TestOnly - public synchronized void storePointers() { - myStoredPointers.clear(); - addAllPointersTo(myStoredPointers); - } - - @TestOnly - public synchronized void assertPointersAreDisposed() { - List pointers = new ArrayList<>(); - addAllPointersTo(pointers); - try { - for (VirtualFilePointerImpl pointer : pointers) { - if (!myStoredPointers.contains(pointer)) { - pointer.throwDisposalError("Virtual pointer '" + pointer + - "' hasn't been disposed: "+pointer.getStackTrace()); - } - } - } - finally { - myStoredPointers.clear(); - } - } - - @TestOnly - private void addAllPointersTo(@NotNull Collection pointers) { + synchronized void addAllPointersTo(@NotNull Collection pointers) { List out = new ArrayList<>(); for (FilePointerPartNode root : myPointers.values()) { root.addPointersUnder(null, false, "", out); diff --git a/platform/platform-impl/src/com/intellij/ui/FontComboBox.java b/platform/platform-impl/src/com/intellij/ui/FontComboBox.java index b3fbb48f3a90..0f4cb2507b54 100644 --- a/platform/platform-impl/src/com/intellij/ui/FontComboBox.java +++ b/platform/platform-impl/src/com/intellij/ui/FontComboBox.java @@ -21,6 +21,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.util.Comparing; import com.intellij.util.ui.FontInfo; +import com.intellij.util.ui.JBDimension; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -39,6 +40,7 @@ public final class FontComboBox extends ComboBox { private static final FontInfoRenderer RENDERER = new FontInfoRenderer(); private Model myModel; + private JBDimension myPrefSize; public FontComboBox() { this(false); @@ -52,7 +54,7 @@ public final class FontComboBox extends ComboBox { super(new Model(withAllStyles, filterNonLatin, noFontItem)); Dimension size = getPreferredSize(); size.width = size.height * 8; - setPreferredSize(size); + myPrefSize = JBDimension.create(size, false); setSwingPopup(true); setRenderer(RENDERER); getModel().addListDataListener(new ListDataListener() { @@ -73,6 +75,13 @@ public final class FontComboBox extends ComboBox { }); } + @Override + public Dimension getPreferredSize() { + if (isPreferredSizeSet() || myPrefSize == null) return super.getPreferredSize(); + myPrefSize.update(); + return myPrefSize; + } + public boolean isMonospacedOnly() { return myModel.myMonospacedOnly; } diff --git a/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java b/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java index b8d59a84f1d8..c0d1c46b6dc6 100755 --- a/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java +++ b/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java @@ -451,6 +451,7 @@ public class SheetController implements Disposable { private void layoutDoNotAskCheckbox(JPanel sheetPanel) { doNotAskCheckBox.setText(myDoNotAskOption.getDoNotShowMessage()); + doNotAskCheckBox.setVisible(myDoNotAskOption.canBeHidden()); doNotAskCheckBox.setSelected(!myDoNotAskOption.isToBeShown()); doNotAskCheckBox.setOpaque(false); doNotAskCheckBox.addItemListener(new ItemListener() { diff --git a/platform/platform-impl/src/com/intellij/ui/plaf/beg/BegMenuItemUI.java b/platform/platform-impl/src/com/intellij/ui/plaf/beg/BegMenuItemUI.java index 851df26d4612..c8e8b4c747cf 100644 --- a/platform/platform-impl/src/com/intellij/ui/plaf/beg/BegMenuItemUI.java +++ b/platform/platform-impl/src/com/intellij/ui/plaf/beg/BegMenuItemUI.java @@ -1,6 +1,6 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,9 @@ package com.intellij.ui.plaf.beg; import com.intellij.ide.ui.UISettings; +import com.intellij.internal.statistic.customUsageCollectors.actions.MainMenuCollector; +import com.intellij.openapi.actionSystem.ActionPlaces; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.impl.ActionMenuItem; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.util.SystemInfo; @@ -509,8 +512,13 @@ public class BegMenuItemUI extends BasicMenuItemUI { if(msm==null){ msm=MenuSelectionManager.defaultManager(); } + ActionMenuItem item = (ActionMenuItem)menuItem; + AnAction action = item.getAnAction(); + if (action != null && ActionPlaces.MAIN_MENU.equals(item.getPlace())) { + MainMenuCollector.getInstance().record(action); + } msm.clearSelectedPath(); - ((ActionMenuItem)menuItem).fireActionPerformed( + item.fireActionPerformed( new ActionEvent( menuItem, ActionEvent.ACTION_PERFORMED, diff --git a/platform/platform-impl/src/com/intellij/ui/tree/AbstractTreeNodeVisitor.java b/platform/platform-impl/src/com/intellij/ui/tree/AbstractTreeNodeVisitor.java new file mode 100644 index 000000000000..3467d8be4809 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/tree/AbstractTreeNodeVisitor.java @@ -0,0 +1,114 @@ +/* + * Copyright 2000-2017 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.tree; + +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.diagnostic.Logger; +import org.jetbrains.annotations.NotNull; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreePath; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public abstract class AbstractTreeNodeVisitor implements TreeVisitor { + protected static final Logger LOG = Logger.getInstance(AbstractTreeNodeVisitor.class); + private final Supplier supplier; + private final Predicate predicate; + + public AbstractTreeNodeVisitor(Supplier supplier, Predicate predicate) { + this.supplier = supplier; + this.predicate = predicate; + } + + public AbstractTreeNodeVisitor(Supplier supplier, Consumer consumer) { + this(supplier, consumer == null ? null : path -> { + consumer.accept(path); + return false; + }); + } + + @NotNull + @Override + public Action accept(@NotNull TreePath path) { + if (LOG.isTraceEnabled()) LOG.debug("process ", path); + T element = supplier == null ? null : supplier.get(); + if (element == null) return Action.SKIP_SIBLINGS; + Object component = path.getLastPathComponent(); + if (component instanceof DefaultMutableTreeNode) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode)component; + Object object = node.getUserObject(); + if (object instanceof AbstractTreeNode) { + return accept(path, (AbstractTreeNode)object, element); + } + else { + LOG.warn(object == null ? "no object" : "unexpected object " + object.getClass()); + } + } + else { + LOG.warn(component == null ? "no component" : "unexpected component " + component.getClass()); + } + return Action.SKIP_CHILDREN; + } + + /** + * @param path a currently visited path + * @param node a node of a tree structure + * @param element an element to find + * @return an action that controls visiting a tree + */ + @NotNull + protected Action accept(@NotNull TreePath path, @NotNull AbstractTreeNode node, @NotNull T element) { + if (found(node, element)) { + LOG.debug("found ", path); + if (predicate == null) return Action.INTERRUPT; + if (predicate.test(path)) return Action.CONTINUE; + } + else if (contains(node, element)) { + LOG.debug("visit ", path); + return Action.CONTINUE; + } + return Action.SKIP_CHILDREN; + } + + /** + * @param node a node of a tree structure + * @param element an element to find + * @return {@code true} if the specified node represents the given element + */ + protected boolean found(@NotNull AbstractTreeNode node, @NotNull T element) { + return node.canRepresent(element); + } + + /** + * @param node a node of a tree structure + * @param element an element to find + * @return {@code true} if the specified node is an ancestor of the given element + */ + protected boolean contains(@NotNull AbstractTreeNode node, @NotNull T element) { + return isAncestor(node.getValue(), element); + } + + /** + * @param value a content of a tree node + * @param element an element to find + * @return + */ + protected boolean isAncestor(Object value, @NotNull T element) { + return false; + } +} diff --git a/platform/platform-impl/src/com/intellij/ui/tree/AbstractTreeWalker.java b/platform/platform-impl/src/com/intellij/ui/tree/AbstractTreeWalker.java index 02464796775a..fdb0625abfe1 100644 --- a/platform/platform-impl/src/com/intellij/ui/tree/AbstractTreeWalker.java +++ b/platform/platform-impl/src/com/intellij/ui/tree/AbstractTreeWalker.java @@ -116,7 +116,7 @@ abstract class AbstractTreeWalker { TreePath result = null; if (node != null) { try { - TreePath path = TreeUtil.createTreePath(parent, converter.apply(node)); + TreePath path = TreePathUtil.createTreePath(parent, converter.apply(node)); switch (visitor.accept(path)) { case CONTINUE: update(null, State.REQUESTED); @@ -171,7 +171,7 @@ abstract class AbstractTreeWalker { current = path.getParentPath(); } else { - TreePath path = TreeUtil.createTreePath(current, converter.apply(node)); + TreePath path = TreePathUtil.createTreePath(current, converter.apply(node)); switch (visitor.accept(path)) { case CONTINUE: update(State.STARTED, State.REQUESTED); diff --git a/platform/platform-impl/src/com/intellij/ui/tree/StructureTreeModel.java b/platform/platform-impl/src/com/intellij/ui/tree/StructureTreeModel.java index 742d6453d3b3..a4b42661f766 100644 --- a/platform/platform-impl/src/com/intellij/ui/tree/StructureTreeModel.java +++ b/platform/platform-impl/src/com/intellij/ui/tree/StructureTreeModel.java @@ -105,6 +105,17 @@ public class StructureTreeModel extends AbstractTreeModel implements Disposable, }); } + public final void invalidate(@NotNull TreePath path) { + invoker.invokeLaterIfNeeded(() -> { + Object component = path.getLastPathComponent(); + if (component instanceof Node) { + Node node = (Node)component; + node.invalidate(); + treeStructureChanged(path, null, null); + } + }); + } + @Override public final Object getRoot() { if (!isValidThread()) return null; diff --git a/platform/platform-impl/src/com/intellij/ui/tree/TreeUtil.java b/platform/platform-impl/src/com/intellij/ui/tree/TreePathUtil.java similarity index 99% rename from platform/platform-impl/src/com/intellij/ui/tree/TreeUtil.java rename to platform/platform-impl/src/com/intellij/ui/tree/TreePathUtil.java index 7c482341e49c..764247cf6e94 100644 --- a/platform/platform-impl/src/com/intellij/ui/tree/TreeUtil.java +++ b/platform/platform-impl/src/com/intellij/ui/tree/TreePathUtil.java @@ -21,7 +21,7 @@ import javax.swing.tree.TreePath; import java.lang.reflect.Array; import java.util.function.Function; -public class TreeUtil { +public class TreePathUtil { /** * @param parent the parent path or {@code null} to indicate the root * @param component the last path component diff --git a/platform/platform-impl/src/org/apache/sanselan/util/IOUtils.java b/platform/platform-impl/src/org/apache/sanselan/util/IOUtils.java new file mode 100644 index 000000000000..30d9ea52f300 --- /dev/null +++ b/platform/platform-impl/src/org/apache/sanselan/util/IOUtils.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2017 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.apache.sanselan.util; + +import com.intellij.openapi.util.io.FileUtil; + +import java.io.*; + +/** + * For plugin compatibility only, DO NOT USE. + * todo check external usages & DELETE ASAP. + *

+ * Required due to sanselan-0.98 -> commons-imaging migration. + * e791557ca1489b02d178aa68960d645ab501e674 + */ +@Deprecated +public class IOUtils { + + public static byte[] getInputStreamBytes(InputStream is) throws IOException { + return FileUtil.loadBytes(is); + } + + public static byte[] getFileBytes(File file) throws IOException { + return FileUtil.loadFileBytes(file); + } + + public static void writeToFile(byte[] src, File file) throws IOException { + FileUtil.writeToFile(file, src); + } + + public static void putInputStreamToFile(InputStream src, File file) throws IOException { + FileUtil.ensureCanCreateFile(file); + copyStreamToStream(src, new FileOutputStream(file), true); + } + + public static void copyStreamToStream(InputStream src, OutputStream dst) throws IOException { + copyStreamToStream(src, dst, true); + } + + public static void copyStreamToStream(InputStream src, OutputStream dst, boolean close_streams) throws IOException { + try { + FileUtil.copy(new BufferedInputStream(src), new BufferedOutputStream(dst)); + } + finally { + if (close_streams) { + try { + src.close(); + } + catch (IOException ignore) { + } + finally { + try { + dst.close(); + } + catch (IOException ignore) { + } + } + } + } + } +} \ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index cca303c18c89..592ba5586e28 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -201,6 +201,7 @@ + + diff --git a/platform/platform-resources/src/META-INF/VcsExtensions.xml b/platform/platform-resources/src/META-INF/VcsExtensions.xml index bf05d2fd9ef1..1912d21ffe08 100644 --- a/platform/platform-resources/src/META-INF/VcsExtensions.xml +++ b/platform/platform-resources/src/META-INF/VcsExtensions.xml @@ -50,6 +50,11 @@ + + + + + diff --git a/platform/platform-resources/src/idea/VcsActions.xml b/platform/platform-resources/src/idea/VcsActions.xml index 1dad5b71986d..479f9d3db021 100644 --- a/platform/platform-resources/src/idea/VcsActions.xml +++ b/platform/platform-resources/src/idea/VcsActions.xml @@ -213,6 +213,22 @@ icon="AllIcons.Vcs.Remove"/> + + + + + + + + + + + + + + @@ -294,7 +310,7 @@ + icon="AllIcons.Welcome.FromVCS"> @@ -383,6 +399,12 @@ + + + + + + diff --git a/platform/platform-tests/testSrc/com/intellij/application/TransactionTest.groovy b/platform/platform-tests/testSrc/com/intellij/application/TransactionTest.groovy index 14debcea1f54..832804b92ea9 100644 --- a/platform/platform-tests/testSrc/com/intellij/application/TransactionTest.groovy +++ b/platform/platform-tests/testSrc/com/intellij/application/TransactionTest.groovy @@ -59,13 +59,11 @@ class TransactionTest extends LightPlatformTestCase { protected void setUp() throws Exception { super.setUp() assert LaterInvocator.currentModalityState == ModalityState.NON_MODAL - TransactionGuardImpl.testingTransactions = true } @Override protected void tearDown() throws Exception { UIUtil.dispatchAllInvocationEvents() - TransactionGuardImpl.testingTransactions = false log.clear() LaterInvocator.leaveAllModals() super.tearDown() diff --git a/platform/platform-tests/testSrc/com/intellij/ide/updates/UpdateInfoParsingTest.kt b/platform/platform-tests/testSrc/com/intellij/ide/updates/UpdateInfoParsingTest.kt index 88b105a492a7..400f3756b18b 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/updates/UpdateInfoParsingTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/ide/updates/UpdateInfoParsingTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,7 +20,9 @@ import com.intellij.openapi.updateSettings.impl.UpdateChannel import com.intellij.openapi.updateSettings.impl.UpdatesInfo import com.intellij.openapi.util.BuildNumber import com.intellij.util.loadElement +import org.junit.Assume.assumeTrue import org.junit.Test +import java.io.IOException import java.net.URL import java.text.SimpleDateFormat import kotlin.test.assertEquals @@ -28,13 +30,23 @@ import kotlin.test.assertNotNull class UpdateInfoParsingTest { @Test fun liveJetbrainsUpdateFile() { - val info = load(URL("http://www.jetbrains.com/updates/updates.xml").readText()) - assertNotNull(info["IC"]) + try { + val info = load(URL("https://www.jetbrains.com/updates/updates.xml").readText()) + assertNotNull(info["IC"]) + } + catch (e: IOException) { + assumeTrue(e.toString(), false) + } } @Test fun liveAndroidUpdateFile() { - val info = load(URL("https://dl.google.com/android/studio/patches/updates.xml").readText()) - assertNotNull(info["AI"]) + try { + val info = load(URL("https://dl.google.com/android/studio/patches/updates.xml").readText()) + assertNotNull(info["AI"]) + } + catch (e: IOException) { + assumeTrue(e.toString(), false) + } } @Test fun emptyChannels() { @@ -66,7 +78,7 @@ class UpdateInfoParsingTest { - IntelliJ IDEA X RC is available. Please visit hhttp://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP to learn more. + IntelliJ IDEA X RC is available. Please visit http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP to learn more.