diff --git a/.idea/modules.xml b/.idea/modules.xml index 1556bf9451d6..494ceb46dbb2 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -565,6 +565,7 @@ + diff --git a/java/compiler/impl/src/com/intellij/compiler/options/ProcessedModulesTable.java b/java/compiler/impl/src/com/intellij/compiler/options/ProcessedModulesTable.java deleted file mode 100644 index 580fbb60cf67..000000000000 --- a/java/compiler/impl/src/com/intellij/compiler/options/ProcessedModulesTable.java +++ /dev/null @@ -1,456 +0,0 @@ -/* - * 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.compiler.options; - -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.module.ModuleType; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ui.configuration.ChooseModulesDialog; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.wm.IdeFocusManager; -import com.intellij.ui.SpeedSearchBase; -import com.intellij.ui.SpeedSearchComparator; -import com.intellij.ui.TableUtil; -import com.intellij.ui.ToolbarDecorator; -import com.intellij.ui.table.JBTable; -import com.intellij.util.ui.EditableModel; -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.table.*; -import java.awt.*; -import java.util.List; -import java.util.*; - -public class ProcessedModulesTable extends JPanel { - private JBTable myTable = null; - private MyTableModel myTableModel = null; - - public ProcessedModulesTable(final Project project) { - super(new BorderLayout()); - - myTableModel = new MyTableModel(project); - myTable = new JBTable(myTableModel); - myTable.getEmptyText().setText("No modules configured"); - - //myTable.setShowGrid(false); - myTable.setIntercellSpacing(JBUI.emptySize()); - myTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); - myTable.setColumnSelectionAllowed(false); - - final TableColumnModel columnModel = myTable.getColumnModel(); - - final TableColumn dirNameColumn = columnModel.getColumn(myTableModel.DIRNAME_COLUMN_INDEX); - final String title = "Generated Sources Directory Name"; - dirNameColumn.setHeaderValue(title); - final JTableHeader tableHeader = myTable.getTableHeader(); - final FontMetrics metrics = tableHeader.getFontMetrics(tableHeader.getFont()); - final int preferredWidth = metrics.stringWidth(title) + 12; - dirNameColumn.setPreferredWidth(preferredWidth); - dirNameColumn.setMaxWidth(preferredWidth + 20); - dirNameColumn.setCellRenderer(new MyElementColumnCellRenderer()); - - final TableColumn moduleColumn = columnModel.getColumn(myTableModel.ELEMENT_COLUMN_INDEX); - moduleColumn.setHeaderValue("Module"); - moduleColumn.setCellRenderer(new MyElementColumnCellRenderer()); - - final JPanel panel = ToolbarDecorator.createDecorator(myTable) - .disableUpDownActions() - .setPreferredSize(JBUI.size(100, 155)) - .createPanel(); - add(panel, BorderLayout.CENTER); - - final SpeedSearchBase speedSearch = new SpeedSearchBase(myTable) { - @Override - public int getSelectedIndex() { - return myTable.getSelectedRow(); - } - - @Override - protected int convertIndexToModel(int viewIndex) { - return myTable.convertRowIndexToModel(viewIndex); - } - - @NotNull - @Override - public Object[] getAllElements() { - final int count = myTableModel.getRowCount(); - Object[] elements = new Object[count]; - for (int idx = 0; idx < count; idx++) { - elements[idx] = myTableModel.getModuleAt(idx); - } - return elements; - } - - @Override - public String getElementText(Object element) { - return ((Module)element).getName() + " (" + FileUtil.toSystemDependentName(((Module)element).getModuleFilePath()) + ")"; - } - - @Override - public void selectElement(Object element, String selectedText) { - final int count = myTableModel.getRowCount(); - for (int row = 0; row < count; row++) { - if (element.equals(myTableModel.getModuleAt(row))) { - final int viewRow = myTable.convertRowIndexToView(row); - myTable.getSelectionModel().setSelectionInterval(viewRow, viewRow); - TableUtil.scrollSelectionToVisible(myTable); - break; - } - } - } - }; - speedSearch.setComparator(new SpeedSearchComparator(false)); - } - - public void refresh() { - myTableModel.fireTableDataChanged(); - } - - public void refresh(Module element) { - final int row = myTableModel.getElementRow(element); - if (row >= 0) { - myTableModel.fireTableRowsUpdated(row, row); - } - } - - private int[] mySavedSelection = null; - public void saveSelection() { - mySavedSelection = myTable.getSelectedRows(); - } - - public void restoreSelection() { - if (mySavedSelection != null) { - TableUtil.selectRows(myTable, mySavedSelection); - mySavedSelection = null; - } - } - - public void addModule(Module element, String dirName) { - myTableModel.addElement(element, dirName); - selectRow(myTableModel.getRowCount() - 1); - IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myTable, true)); - } - - public void removeModule(Module element) { - final int elementRow = myTableModel.getElementRow(element); - if (elementRow < 0) { - return; // no such element - } - final boolean wasSelected = myTable.getSelectionModel().isSelectedIndex(elementRow); - - myTableModel.removeElement(element); - - if (wasSelected) { - final int rowCount = myTableModel.getRowCount(); - if (rowCount > 0) { - selectRow(elementRow % rowCount); - } - else { - myTable.getSelectionModel().clearSelection(); - } - } - IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myTable, true)); - } - - public void removeAllElements() { - myTableModel.removeAllElements(); - myTable.getSelectionModel().clearSelection(); - } - - private void selectRow(final int row) { - myTable.getSelectionModel().setSelectionInterval(row, row); - myTable.scrollRectToVisible(myTable.getCellRect(row, 0, true)); - } - - @Nullable - public Module getSelectedElement() { - final int selectedRow = getSelectedElementRow(); - return selectedRow < 0? null : myTableModel.getModuleAt(selectedRow); - } - - public int getSelectedElementRow() { - return myTable.getSelectedRow(); - } - - public List getSelectedElements() { - final List elements = new ArrayList<>(); - final int[] selectedRows = myTable.getSelectedRows(); - for (int selectedRow : selectedRows) { - if (selectedRow < 0) { - continue; - } - elements.add(myTableModel.getModuleAt(selectedRow)); - } - return elements; - } - - public void selectElements(Collection elements) { - if (elements.size() == 0) { - myTable.clearSelection(); - return; - } - final int[] rows = getElementsRows(elements); - TableUtil.selectRows(myTable, rows); - TableUtil.scrollSelectionToVisible(myTable); - IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myTable, true)); - } - - private int[] getElementsRows(final Collection elements) { - final int[] rows = new int[elements.size()]; - int index = 0; - for (final Module element : elements) { - rows[index++] = myTableModel.getElementRow(element); - } - return rows; - } - - public List> getAllModules() { - final int count = myTableModel.getRowCount(); - List> elements = new ArrayList<>(); - for (int idx = 0; idx < count; idx++) { - final Module module = myTableModel.getModuleAt(idx); - elements.add(Pair.create(module, myTableModel.getGenDirName(module))); - } - return elements; - } - - public void sort(Comparator comparator) { - myTableModel.sort(comparator); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - myTable.setRowSelectionAllowed(enabled); - myTableModel.fireTableDataChanged(); - } - - public void stopEditing() { - TableCellEditor editor = myTable.getCellEditor(); - if (editor != null) { - editor.stopCellEditing(); - } - } - - public JComponent getComponent() { - return myTable; - } - - public void clear() { - myTableModel.clear(); - } - - public int getElementCount() { - return myTableModel.getRowCount(); - } - - public Module getElementAt(int row) { - return myTableModel.getModuleAt(row); - } - - private final class MyTableModel extends AbstractTableModel implements EditableModel { - private final List myElements = new ArrayList<>(); - private final Map myDirNameMap = new HashMap<>(); - public final int ELEMENT_COLUMN_INDEX = 0; - public final int DIRNAME_COLUMN_INDEX = 1; - private final Project myProject; - - private MyTableModel(Project project) { - myProject = project; - } - - public void sort(Comparator comparator) { - Collections.sort(myElements, comparator); - fireTableDataChanged(); - } - - public List getAllModules() { - return Collections.unmodifiableList(myElements); - } - - public Module getModuleAt(int index) { - return myElements.get(index); - } - - public String getGenDirName(Module module) { - return myDirNameMap.get(module); - } - - void addElement(Module module, final String dirName) { - myElements.add(module); - if (dirName != null && dirName.length() > 0) { - myDirNameMap.put(module, dirName); - } - int row = myElements.size() - 1; - fireTableRowsInserted(row, row); - } - - @Override - public void addRow() { - final Set projectModules = new HashSet<>(Arrays.asList(ModuleManager.getInstance(myProject).getModules())); - projectModules.removeAll(getAllModules()); - final ChooseModulesDialog chooser = - new ChooseModulesDialog(ProcessedModulesTable.this, new ArrayList<>(projectModules), "ChooseModule"); - if (chooser.showAndGet()) { - final List chosen = chooser.getChosenElements(); - for (Module module : chosen) { - addElement(module, null); - } - } - } - - @Override - public void removeRow(int idx) { - final Module element = myElements.remove(idx); - myDirNameMap.remove(element); - fireTableRowsDeleted(idx, idx); - } - - @Override - public void exchangeRows(int oldIndex, int newIndex) { - } - - @Override - public boolean canExchangeRows(int oldIndex, int newIndex) { - return false; - } - - public void removeElement(Module element) { - final boolean reallyRemoved = myElements.remove(element); - if (reallyRemoved) { - myDirNameMap.remove(element); - fireTableDataChanged(); - } - } - - public int getElementRow(Module element) { - return myElements.indexOf(element); - } - - public void removeAllElements() { - myElements.clear(); - fireTableDataChanged(); - } - - @Override - public int getRowCount() { - return myElements.size(); - } - - @Override - public int getColumnCount() { - return 2; - } - - @Override - @Nullable - public Object getValueAt(int rowIndex, int columnIndex) { - Module element = myElements.get(rowIndex); - if (columnIndex == ELEMENT_COLUMN_INDEX) { - return element; - } - if (columnIndex == DIRNAME_COLUMN_INDEX) { - return myDirNameMap.get(element); - } - return null; - } - - @Override - public void setValueAt(Object value, int rowIndex, int columnIndex) { - if (columnIndex == DIRNAME_COLUMN_INDEX) { - final Module module = myElements.get(rowIndex); - if (value != null) { - String dir = FileUtil.toSystemIndependentName((String)value); - while (dir.startsWith("/")) { - dir = dir.substring(1); - } - if (dir.length() > 0) { - myDirNameMap.put(module, dir); - } - else { - myDirNameMap.remove(module); - } - } - else { - myDirNameMap.remove(module); - } - fireTableRowsUpdated(rowIndex, rowIndex); - } - } - - @Override - public Class getColumnClass(int columnIndex) { - if (columnIndex == DIRNAME_COLUMN_INDEX) { - return String.class; - } - return super.getColumnClass(columnIndex); - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - if (!ProcessedModulesTable.this.isEnabled()) { - return false; - } - if (columnIndex == DIRNAME_COLUMN_INDEX) { - return true; - } - return false; - } - - public void clear() { - myElements.clear(); - myDirNameMap.clear(); - fireTableDataChanged(); - } - } - - private class MyElementColumnCellRenderer extends DefaultTableCellRenderer { - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - final Color color = UIUtil.getTableFocusCellBackground(); - Component component; - final Module module = value instanceof Module? (Module)value : null; - try { - UIManager.put(UIUtil.TABLE_FOCUS_CELL_BACKGROUND_PROPERTY, table.getSelectionBackground()); - component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - if (module != null) { - setText(module.getName() + " (" + FileUtil.toSystemDependentName(module.getModuleFilePath()) + ")"); - } - if (component instanceof JLabel) { - ((JLabel)component).setBorder(noFocusBorder); - } - } - finally { - UIManager.put(UIUtil.TABLE_FOCUS_CELL_BACKGROUND_PROPERTY, color); - } - component.setEnabled(ProcessedModulesTable.this.isEnabled()); - if (component instanceof JLabel) { - final Icon icon = module != null ? ModuleType.get(module).getIcon() : null; - JLabel label = (JLabel)component; - label.setIcon(icon); - label.setDisabledIcon(icon); - } - component.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground()); - return component; - } - } -} diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java deleted file mode 100644 index 17739b154aa6..000000000000 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2000-2014 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.compiler.generic; - -import com.intellij.util.io.DataExternalizer; -import org.jetbrains.annotations.NotNull; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** -* @author nik -*/ -public class VirtualFilePersistentState { - public static DataExternalizer EXTERNALIZER = new VirtualFileStateExternalizer(); - private final long mySourceTimestamp; - - public VirtualFilePersistentState(long sourceTimestamp) { - mySourceTimestamp = sourceTimestamp; - } - - public final long getSourceTimestamp() { - return mySourceTimestamp; - } - - private static class VirtualFileStateExternalizer implements DataExternalizer { - @Override - public void save(@NotNull DataOutput out, VirtualFilePersistentState value) throws IOException { - out.writeLong(value.getSourceTimestamp()); - } - - @Override - public VirtualFilePersistentState read(@NotNull DataInput in) throws IOException { - return new VirtualFilePersistentState(in.readLong()); - } - - } -} diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java deleted file mode 100644 index 1dc4fe6e49ca..000000000000 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2000-2014 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.compiler.generic; - -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.io.DataExternalizer; -import com.intellij.util.io.IOUtil; -import org.jetbrains.annotations.NotNull; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * @author nik - */ -public class VirtualFileSetState { - public static final DataExternalizer EXTERNALIZER = new VirtualFileWithDependenciesExternalizer(); - private final Map myTimestamps = new HashMap<>(); - - public VirtualFileSetState() { - } - - public VirtualFileSetState(Collection files) { - for (VirtualFile file : files) { - addFile(file); - } - } - - public void addFile(@NotNull VirtualFile file) { - myTimestamps.put(file.getUrl(), file.getTimeStamp()); - } - - public boolean isUpToDate(Set files) { - if (files.size() != myTimestamps.size()) { - return false; - } - - for (VirtualFile file : files) { - final Long timestamp = myTimestamps.get(file.getUrl()); - if (timestamp == null || timestamp != file.getTimeStamp()) { - return false; - } - } - return true; - } - - - private static class VirtualFileWithDependenciesExternalizer implements DataExternalizer { - @Override - public void save(@NotNull DataOutput out, VirtualFileSetState value) throws IOException { - final Map dependencies = value.myTimestamps; - out.writeInt(dependencies.size()); - for (Map.Entry entry : dependencies.entrySet()) { - IOUtil.writeUTF(out, entry.getKey()); - out.writeLong(entry.getValue()); - } - } - - @Override - public VirtualFileSetState read(@NotNull DataInput in) throws IOException { - final VirtualFileSetState state = new VirtualFileSetState(); - int size = in.readInt(); - while (size-- > 0) { - final String url = IOUtil.readUTF(in); - final long timestamp = in.readLong(); - state.myTimestamps.put(url, timestamp); - } - return state; - } - } -} diff --git a/java/compiler/openapi/src/com/intellij/packaging/elements/ArtifactIncrementalCompilerContext.java b/java/compiler/openapi/src/com/intellij/packaging/elements/ArtifactIncrementalCompilerContext.java index 6ee65f524f8d..00e3a951d024 100644 --- a/java/compiler/openapi/src/com/intellij/packaging/elements/ArtifactIncrementalCompilerContext.java +++ b/java/compiler/openapi/src/com/intellij/packaging/elements/ArtifactIncrementalCompilerContext.java @@ -15,8 +15,12 @@ */ package com.intellij.packaging.elements; +import org.jetbrains.annotations.ApiStatus; + /** - * @author nik + * @deprecated this interface was used in the old build infrastructure, it doesn't make sense anymore */ +@ApiStatus.ScheduledForRemoval(inVersion = "192.0") +@Deprecated public interface ArtifactIncrementalCompilerContext { } diff --git a/java/compiler/tests/com/intellij/compiler/IOUtilTest.java b/java/compiler/tests/com/intellij/compiler/IOUtilTest.java index 713aac1f5da1..f17be223b042 100644 --- a/java/compiler/tests/com/intellij/compiler/IOUtilTest.java +++ b/java/compiler/tests/com/intellij/compiler/IOUtilTest.java @@ -14,7 +14,7 @@ import java.io.*; */ public class IOUtilTest extends TestCase { - private static interface IO { + private interface IO { void save(String str, DataOutput out) throws IOException; String load(DataInput in) throws IOException; } diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/StepOutOfBlockAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/StepOutOfBlockAction.java index dccca4e42761..a156222e8b20 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/StepOutOfBlockAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/StepOutOfBlockAction.java @@ -12,8 +12,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiCodeBlock; -import com.intellij.psi.PsiElement; +import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Range; import com.intellij.xdebugger.XDebugProcess; @@ -45,16 +44,25 @@ public class StepOutOfBlockAction extends DebuggerAction implements DumbAware { SourcePosition position = debuggerContext.getSourcePosition(); if (position != null && session != null) { PsiElement element = position.getElementAt(); - PsiCodeBlock block = PsiTreeUtil.getParentOfType(element, PsiCodeBlock.class); - if (block != null) { - TextRange textRange = block.getTextRange(); - Document document = FileDocumentManager.getInstance().getDocument(position.getFile().getVirtualFile()); - if (document != null) { - int startLine = document.getLineNumber(textRange.getStartOffset()); - int endLine = document.getLineNumber(textRange.getEndOffset()); - session.sessionResumed(); - session.stepOver(false, new BlockFilter(startLine, endLine), StepRequest.STEP_LINE); + PsiElement block = PsiTreeUtil.getParentOfType(element, PsiCodeBlock.class, PsiLambdaExpression.class); + if (block instanceof PsiCodeBlock) { + PsiElement parent = block.getParent(); + if (parent instanceof PsiMethod || parent instanceof PsiLambdaExpression) { + xSession.stepOut(); } + else { + TextRange textRange = block.getTextRange(); + Document document = FileDocumentManager.getInstance().getDocument(position.getFile().getVirtualFile()); + if (document != null) { + int startLine = document.getLineNumber(textRange.getStartOffset()); + int endLine = document.getLineNumber(textRange.getEndOffset()); + session.sessionResumed(); + session.stepOver(false, new BlockFilter(startLine, endLine), StepRequest.STEP_LINE); + } + } + } + else { + xSession.stepOut(); } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index af17d6c4b073..1a372e34aafa 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.debugger.engine; import com.intellij.debugger.MultiRequestPositionManager; @@ -337,8 +337,8 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio PsiFile[] files = FilenameIndex.getFilesByName(project, refType.sourceName(), GlobalSearchScope.allScope(project)); for (PsiFile file : files) { if (file instanceof PsiJavaFile) { - for (PsiClass cls : ((PsiJavaFile)file).getClasses()) { - if (StringUtil.equals(originalQName, cls.getQualifiedName())) { + for (PsiClass cls : PsiTreeUtil.findChildrenOfAnyType(file, PsiClass.class)) { + if (StringUtil.equals(originalQName, JVMNameUtil.getClassVMName(cls))) { return file; } } diff --git a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java index d69953e5cb14..eede8ff52145 100644 --- a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java +++ b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java @@ -282,11 +282,13 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner { myProcessHandler.addProcessListener(new ProcessAdapter() { @Override public void startNotified(@NotNull ProcessEvent event) { - // 1 second delay to allow jvm to start correctly - JobScheduler.getScheduler() - .schedule(() -> myEnabled.set(!myProcessHandler.isProcessTerminating() && !myProcessHandler.isProcessTerminated() && - JavaDebuggerAttachUtil.canAttach(OSProcessUtil.getProcessID(myProcessHandler.getProcess()))), - 1, TimeUnit.SECONDS); + if (!ApplicationManager.getApplication().isUnitTestMode()) { + // 1 second delay to allow jvm to start correctly + JobScheduler.getScheduler() + .schedule(() -> myEnabled.set(!myProcessHandler.isProcessTerminating() && !myProcessHandler.isProcessTerminated() && + JavaDebuggerAttachUtil.canAttach(OSProcessUtil.getProcessID(myProcessHandler.getProcess()))), + 1, TimeUnit.SECONDS); + } } @Override diff --git a/java/execution/impl/src/com/intellij/execution/jshell/ExecuteJShellAction.java b/java/execution/impl/src/com/intellij/execution/jshell/ExecuteJShellAction.java index ecc3295ee03d..5be40ac7cab5 100644 --- a/java/execution/impl/src/com/intellij/execution/jshell/ExecuteJShellAction.java +++ b/java/execution/impl/src/com/intellij/execution/jshell/ExecuteJShellAction.java @@ -26,7 +26,7 @@ import org.jetbrains.annotations.Nullable; */ class ExecuteJShellAction extends AnAction{ private static final AnAction ourInstance = new ExecuteJShellAction(); - private final boolean myIsExecuteContextElement = false; + private static final boolean myIsExecuteContextElement = false; private ExecuteJShellAction() { super(AllIcons.Toolwindows.ToolWindowRun); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java index cdf5517de5f3..6b8560f9ceaa 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java @@ -13,6 +13,7 @@ import com.intellij.codeInspection.dataFlow.fix.*; import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.value.DfaConstValue; import com.intellij.codeInspection.nullable.NullableStuffInspectionBase; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; @@ -195,7 +196,8 @@ public class DataFlowInspectionBase extends AbstractBaseJavaLocalInspectionTool final DataFlowInstructionVisitor visitor = new DataFlowInstructionVisitor(); final RunnerResult rc = dfaRunner.analyzeMethod(scope, visitor, IGNORE_ASSERT_STATEMENTS, initialStates); if (rc == RunnerResult.OK) { - if (dfaRunner.wasForciblyMerged() && Registry.is("ide.dfa.report.imprecise")) { + if (dfaRunner.wasForciblyMerged() && + (ApplicationManager.getApplication().isUnitTestMode() || Registry.is("ide.dfa.report.imprecise"))) { reportAnalysisQualityProblem(holder, scope, "dataflow.not.precise"); } createDescription(dfaRunner, holder, visitor, scope); diff --git a/java/java-impl/src/META-INF/libraryJarUsage.xml b/java/java-impl/src/META-INF/libraryJarUsage.xml index 0192efe1b571..0c99b9031cd0 100644 --- a/java/java-impl/src/META-INF/libraryJarUsage.xml +++ b/java/java-impl/src/META-INF/libraryJarUsage.xml @@ -1,7 +1,6 @@ - diff --git a/java/java-impl/src/com/intellij/application/options/editor/ExcludeTable.java b/java/java-impl/src/com/intellij/application/options/editor/ExcludeTable.java index 4812b37cdd6c..4268497c9e43 100644 --- a/java/java-impl/src/com/intellij/application/options/editor/ExcludeTable.java +++ b/java/java-impl/src/com/intellij/application/options/editor/ExcludeTable.java @@ -5,14 +5,23 @@ import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.JavaProjectCodeInsightSettings; import com.intellij.execution.util.ListTableWithButtons; import com.intellij.icons.AllIcons; +import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComboBoxTableRenderer; +import com.intellij.openapi.ui.ComponentValidator; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.ui.cellvalidators.CellComponentProvider; +import com.intellij.openapi.ui.cellvalidators.CellTooltipManager; +import com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper; +import com.intellij.openapi.ui.cellvalidators.ValidationUtils; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; -import com.intellij.ui.DocumentAdapter; -import com.intellij.ui.GuiUtils; -import com.intellij.ui.JBColor; import com.intellij.ui.ScrollingUtil; +import com.intellij.ui.components.fields.ExtendableTextField; +import com.intellij.ui.table.JBTable; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.ColumnInfo; @@ -22,20 +31,26 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.DocumentEvent; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; -import java.awt.*; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.function.BiFunction; import java.util.regex.Pattern; class ExcludeTable extends ListTableWithButtons { private static final Pattern ourPackagePattern = Pattern.compile("([\\w*]+\\.)*[\\w*]+"); + + private static final BiFunction validationInfoProducer = (value, component) -> + (value == null || StringUtil.isEmpty(value.toString()) || ourPackagePattern.matcher(value.toString()).matches()) ? + null : new ValidationInfo("Illegal name: " + value.toString(), component); + + private static final Disposable validatorsDisposable = Disposer.newDisposable(); private static final ColumnInfo NAME_COLUMN = new ColumnInfo("Class/package/member qualified name mask") { + @Nullable @Override public String valueOf(Item pair) { @@ -44,35 +59,24 @@ class ExcludeTable extends ListTableWithButtons { @Override public TableCellEditor getEditor(Item pair) { - final JTextField field = GuiUtils.createUndoableTextField(); - field.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(@NotNull DocumentEvent e) { - field.putClientProperty("JComponent.outline", - ourPackagePattern.matcher(field.getText()).matches() ? null : "error"); - } - }); - return new DefaultCellEditor(field); + ExtendableTextField cellEditor = new ExtendableTextField(); + cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE); + + new ComponentValidator(validatorsDisposable).withValidator(() -> { + String text = cellEditor.getText(); + boolean hasError = !StringUtil.isEmpty(text) && !ourPackagePattern.matcher(text).matches(); + ValidationUtils.setExtension(cellEditor, ValidationUtils.ERROR_EXTENSION, hasError); + + return validationInfoProducer.apply(text, cellEditor); + }).andRegisterOnDocumentListener(cellEditor).installOn(cellEditor); + + return new DefaultCellEditor(cellEditor); } @Override public TableCellRenderer getRenderer(Item pair) { - return new DefaultTableCellRenderer() { - @NotNull - @Override - public Component getTableCellRendererComponent(JTable table, - Object value, - boolean isSelected, - boolean hasFocus, - int row, - int column) { - Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - if (!ourPackagePattern.matcher((String)value).matches()) { - component.setForeground(JBColor.RED); - } - return component; - } - }; + return new ValidatingTableCellRendererWrapper(new DefaultTableCellRenderer()). + withCellValidator((value, row, column) -> validationInfoProducer.apply(value, null)); } @Override @@ -85,6 +89,7 @@ class ExcludeTable extends ListTableWithButtons { item.exclude = value; } }; + private static final ColumnInfo SCOPE_COLUMN = new ColumnInfo("Scope") { @Nullable @Override @@ -126,7 +131,13 @@ class ExcludeTable extends ListTableWithButtons { ExcludeTable(@NotNull Project project) { myProject = project; - getTableView().getEmptyText().setText(ApplicationBundle.message("exclude.from.imports.no.exclusions")); + + JBTable table = getTableView(); + table.getEmptyText().setText(ApplicationBundle.message("exclude.from.imports.no.exclusions")); + table.setStriped(false); + new CellTooltipManager(myProject).withCellComponentProvider(CellComponentProvider.forTable(table)).installOn(table); + + Disposer.register(project, validatorsDisposable); } @Override @@ -175,7 +186,7 @@ class ExcludeTable extends ListTableWithButtons { } void reset() { - java.util.List rows = ContainerUtil.newArrayList(); + List rows = ContainerUtil.newArrayList(); for (String s : CodeInsightSettings.getInstance().EXCLUDED_PACKAGES) { rows.add(new Item(s, ExclusionScope.IDE)); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java index e87f5e864110..01e36e1d1744 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java @@ -18,6 +18,7 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.undo.UndoUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; @@ -320,6 +321,9 @@ public class ChangeMethodSignatureFromUsageFix implements IntentionAction/*, Hig try { PsiUtil.ensureValidType(bareParamType); } + catch (ProcessCanceledException e) { + throw e; + } catch (Throwable e) { throw PluginException.createByClass( parameter.getClass() + "; valid=" + parameter.isValid() + "; method.valid=" + targetMethod.isValid(), diff --git a/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java b/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java index c69c35555266..7dd92fa566d1 100644 --- a/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java @@ -275,27 +275,23 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { private static class MergeBranchesFix implements LocalQuickFix { @NotNull private final String mySwitchLabelText; - private final boolean myInExpression; - MergeBranchesFix(@NotNull String switchLabelText, boolean inExpression) { + MergeBranchesFix(@NotNull String switchLabelText) { mySwitchLabelText = switchLabelText; - myInExpression = inExpression; } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getFamilyName() { - return myInExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.expression.fix.family.name") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.fix.family.name"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.merge.fix.family.name"); } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getName() { - return InspectionsBundle.message("inspection.duplicate.branches.in.switch.fix.name", mySwitchLabelText); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.merge.fix.name", mySwitchLabelText); } @Override @@ -329,26 +325,19 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { } private static class DeleteRedundantBranchFix implements LocalQuickFix { - private final boolean myInExpression; - - private DeleteRedundantBranchFix(boolean inExpression) { - myInExpression = inExpression; - } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getName() { - return InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.fix.name"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.delete.fix.name"); } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getFamilyName() { - return myInExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.expression.fix.family.name") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.fix.family.name"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.delete.fix.family.name"); } @Override @@ -478,7 +467,6 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { @NotNull protected final T myLabel; @NotNull protected final PsiStatement[] myStatements; @NotNull protected final String[] myCommentTexts; - protected final boolean myInExpression; private final boolean myIsDefault; private DuplicatesFinder myFinder; @@ -489,7 +477,6 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { myLabel = labels[0]; myStatements = statements; myCommentTexts = commentTexts; - myInExpression = PsiTreeUtil.getParentOfType(labels[0], PsiSwitchBlock.class) instanceof PsiSwitchExpression; myIsDefault = ContainerUtil.find(labels, PsiSwitchLabelStatementBase::isDefaultCase) != null; } @@ -538,15 +525,11 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { } String getCaseBranchMessage() { - return myInExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.expression.message") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.statement.message"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.message"); } String getDefaultBranchMessage() { - return myInExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.expression.default.message") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.statement.default.message"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.default.message"); } @Override @@ -681,7 +664,7 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { @Override LocalQuickFix newMergeCasesFix() { String switchLabelText = getSwitchLabelText(); - return switchLabelText != null ? new MergeBranchesFix(switchLabelText, myInExpression) : null; + return switchLabelText != null ? new MergeBranchesFix(switchLabelText) : null; } @Override @@ -691,7 +674,7 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { @Override LocalQuickFix newDeleteCaseFix() { - return new DeleteRedundantBranchFix(myInExpression); + return new DeleteRedundantBranchFix(); } /** @@ -798,7 +781,6 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { } private static class Rule extends BranchBase { - private final boolean myIsResult; private final boolean myIsSimpleExit; Rule(@NotNull PsiSwitchLabeledRuleStatement rule, @NotNull PsiStatement body, @NotNull String[] commentTexts) { @@ -806,7 +788,6 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { new PsiStatement[]{body}, commentTexts); - myIsResult = body instanceof PsiExpressionStatement; myIsSimpleExit = body instanceof PsiExpressionStatement || body instanceof PsiThrowStatement; } @@ -820,31 +801,11 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { return false; } - @Override - String getCaseBranchMessage() { - if (myInExpression) { - return myIsResult - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.result.message") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.expression.message"); - } - return super.getCaseBranchMessage(); - } - - @Override - String getDefaultBranchMessage() { - if (myInExpression) { - return myIsResult - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.default.result.message") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.expression.default.message"); - } - return super.getDefaultBranchMessage(); - } - @Nullable @Override LocalQuickFix newMergeCasesFix() { String switchLabelText = getSwitchLabelText(); - return switchLabelText != null ? new MergeRulesFix(switchLabelText, isResultExpression()) : null; + return switchLabelText != null ? new MergeRulesFix(switchLabelText) : null; } @Override @@ -854,37 +815,29 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { @Override LocalQuickFix newDeleteCaseFix() { - return new DeleteRedundantRuleFix(isResultExpression()); - } - - private boolean isResultExpression() { - return myInExpression && myIsResult; + return new DeleteRedundantRuleFix(); } } private static class MergeRulesFix implements LocalQuickFix { @NotNull private final String mySwitchLabelText; - private final boolean myIsResultExpression; - MergeRulesFix(@NotNull String switchLabelText, boolean isResultExpression) { + MergeRulesFix(@NotNull String switchLabelText) { mySwitchLabelText = switchLabelText; - myIsResultExpression = isResultExpression; } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getFamilyName() { - return myIsResultExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.expression.fix.family.name") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.fix.family.name"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.merge.fix.family.name"); } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getName() { - return InspectionsBundle.message("inspection.duplicate.branches.in.switch.fix.name", mySwitchLabelText); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.merge.fix.name", mySwitchLabelText); } @Override @@ -898,28 +851,19 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { } private static class DeleteRedundantRuleFix implements LocalQuickFix { - private final boolean myIsResultExpression; - - DeleteRedundantRuleFix(boolean isResultExpression) { - myIsResultExpression = isResultExpression; - } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getName() { - return myIsResultExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.expression.fix.name") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.fix.name"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.delete.fix.name"); } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getFamilyName() { - return myIsResultExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.expression.fix.family.name") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.fix.family.name"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.delete.fix.family.name"); } @Override diff --git a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java index 66b5c92f0113..a203d62f35f5 100644 --- a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java @@ -69,6 +69,7 @@ public class JavaDocReferenceInspection extends LocalInspectionTool { boolean allAccessible = !REPORT_INACCESSIBLE || Arrays.stream(resolveResults).map(ResolveResult::getElement) + .filter(Objects::nonNull) .allMatch(element -> isAccessible(element, context)); return allAccessible ? null : diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java index acbf7bece84c..d5c54e5ed308 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java @@ -38,7 +38,6 @@ import javax.swing.*; import java.awt.*; import java.util.List; import java.util.*; -import java.util.stream.Collectors; public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTool { @NonNls public static final String SHORT_NAME = "FieldCanBeLocal"; @@ -376,22 +375,30 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo private static class ConvertFieldToLocalQuickFix extends BaseConvertToLocalQuickFix { private final String myName; - private ConvertFieldToLocalQuickFix(Map> refs) { - Set methods = refs.keySet().stream() - .filter(block -> block.getParent() instanceof PsiMethod) - .map(block -> (PsiMethod)block.getParent()) - .collect(Collectors.toSet()); + private ConvertFieldToLocalQuickFix(@NotNull Map> refs) { + final Set blocks = refs.keySet(); + final PsiElement block; + if (blocks.size() == 1) { + block = + PsiTreeUtil.getNonStrictParentOfType(blocks.toArray(PsiCodeBlock.EMPTY_ARRAY)[0], PsiClassInitializer.class, PsiMethod.class); + } + else { + block = null; + } - myName = determineName(methods, refs); + myName = determineName(block); } @NotNull - private String determineName(Set methods, Map> refs) { - if (methods.isEmpty() || methods.size() != refs.size()) return getFamilyName(); - if (methods.size() > 1) return InspectionsBundle.message("inspection.field.can.be.local.quickfix.multiple.methods", methods.size()); + private String determineName(@Nullable PsiElement block) { + if (block instanceof PsiClassInitializer) return InspectionsBundle.message("inspection.field.can.be.local.quickfix.initializer"); - final String methodName = methods.toArray(PsiMethod.EMPTY_ARRAY)[0].getName(); - return InspectionsBundle.message("inspection.field.can.be.local.quickfix.one.method", methodName); + if (block instanceof PsiMethod) { + if (((PsiMethod)block).isConstructor()) return InspectionsBundle.message("inspection.field.can.be.local.quickfix.constructor"); + return InspectionsBundle.message("inspection.field.can.be.local.quickfix.one.method", ((PsiMethod)block).getName()); + } + + return getFamilyName(); } @NotNull diff --git a/java/java-impl/src/com/intellij/internal/statistic/libraryJar/FUSLibraryJarUsagesCollector.java b/java/java-impl/src/com/intellij/internal/statistic/libraryJar/FUSLibraryJarUsagesCollector.java index a60cbab7d26c..9997555154a1 100644 --- a/java/java-impl/src/com/intellij/internal/statistic/libraryJar/FUSLibraryJarUsagesCollector.java +++ b/java/java-impl/src/com/intellij/internal/statistic/libraryJar/FUSLibraryJarUsagesCollector.java @@ -2,6 +2,7 @@ package com.intellij.internal.statistic.libraryJar; import com.intellij.internal.statistic.beans.UsageDescriptor; +import com.intellij.internal.statistic.eventLog.FeatureUsageData; import com.intellij.internal.statistic.service.fus.collectors.ProjectUsagesCollector; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; @@ -45,11 +46,9 @@ public class FUSLibraryJarUsagesCollector extends ProjectUsagesCollector { VirtualFile jarFile = JarFileSystem.getInstance().getVirtualFileForJar(psiClass.getContainingFile().getVirtualFile()); if (jarFile != null) { String version = getVersionByJarManifest(jarFile); - if (version == null) { - version = getVersionByJarFileName(jarFile.getName()); - } - if (version != null && StringUtil.containsChar(version, '.')) { - result.add(new UsageDescriptor(descriptor.myName + "_" + version, 1)); + if (version == null) version = getVersionByJarFileName(jarFile.getName()); + if (StringUtil.isNotEmpty(version)) { + result.add(new UsageDescriptor(descriptor.myName, 1, new FeatureUsageData().addOS().addVersionByString(version))); } } } @@ -75,6 +74,6 @@ public class FUSLibraryJarUsagesCollector extends ProjectUsagesCollector { @NotNull @Override public String getGroupId() { - return "javaLibraries"; + return "javaLibraryJars"; } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/internal/statistic/libraryJar/LibraryJarStatisticsService.java b/java/java-impl/src/com/intellij/internal/statistic/libraryJar/LibraryJarStatisticsService.java index 56603aac3b7b..75ddc4ce8905 100644 --- a/java/java-impl/src/com/intellij/internal/statistic/libraryJar/LibraryJarStatisticsService.java +++ b/java/java-impl/src/com/intellij/internal/statistic/libraryJar/LibraryJarStatisticsService.java @@ -35,7 +35,7 @@ import java.net.URL; /** * @author Ivan Chirkov */ -public class LibraryJarStatisticsService implements StartupActivity, DumbAware { +public class LibraryJarStatisticsService implements DumbAware { private static final String FILE_NAME = "statistics/library-jar-statistics.xml"; @@ -90,11 +90,4 @@ public class LibraryJarStatisticsService implements StartupActivity, DumbAware { return null; } - - @Override - public void runActivity(@NotNull Project project) { - final Application application = ApplicationManager.getApplication(); - if (application.isUnitTestMode() || application.isHeadlessEnvironment()) return; - ApplicationManager.getApplication().executeOnPooledThread((Runnable)() -> getInstance().getTechnologyDescriptors()); - } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index 94c8cf98a71b..e960e0246f20 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -329,9 +329,18 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { if (statements.length == 1) { if (statements[0] instanceof PsiExpressionStatement) { tempExpr = ((PsiExpressionStatement) statements[0]).getExpression(); - } else if (statements[0] instanceof PsiReturnStatement) { + } + else if (statements[0] instanceof PsiReturnStatement) { tempExpr = ((PsiReturnStatement)statements[0]).getReturnValue(); } + else if (statements[0] instanceof PsiSwitchStatement) { + PsiExpression expr = JavaPsiFacade.getElementFactory(project).createExpressionFromText(statements[0].getText(), statements[0]); + TextRange range = statements[0].getTextRange(); + final RangeMarker rangeMarker = FileDocumentManager.getInstance().getDocument(file.getVirtualFile()).createRangeMarker(range); + expr.putUserData(ElementToWorkOn.TEXT_RANGE, rangeMarker); + expr.putUserData(ElementToWorkOn.PARENT, statements[0]); + return expr; + } } } diff --git a/java/java-impl/src/com/intellij/util/xml/converters/ClassArrayConverterImpl.java b/java/java-impl/src/com/intellij/util/xml/converters/ClassArrayConverterImpl.java index a7e2dd308fcd..07ace6f972b1 100644 --- a/java/java-impl/src/com/intellij/util/xml/converters/ClassArrayConverterImpl.java +++ b/java/java-impl/src/com/intellij/util/xml/converters/ClassArrayConverterImpl.java @@ -25,6 +25,7 @@ import com.intellij.util.xml.converters.values.ClassArrayConverter; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class ClassArrayConverterImpl extends ClassArrayConverter { @@ -66,10 +67,7 @@ public class ClassArrayConverterImpl extends ClassArrayConverter { } private static void createReference(final PsiElement element, final String s, final int offset, List list) { - final PsiReference[] references = REFERENCE_PROVIDER.getReferencesByString(s, element, offset); - //noinspection ManualArrayToCollectionCopy - for (PsiReference ref: references) { - list.add(ref); - } + PsiReference[] references = REFERENCE_PROVIDER.getReferencesByString(s, element, offset); + list.addAll(Arrays.asList(references)); } } diff --git a/java/java-impl/src/inspectionDescriptions/ExcessiveRangeCheck.html b/java/java-impl/src/inspectionDescriptions/ExcessiveRangeCheck.html index db5eed4edb1d..c26369c2afa7 100644 --- a/java/java-impl/src/inspectionDescriptions/ExcessiveRangeCheck.html +++ b/java/java-impl/src/inspectionDescriptions/ExcessiveRangeCheck.html @@ -1,6 +1,6 @@ -Reports condition chains where value range is checked which could be simplified to single check. E.g. x > 2 && x < 4 could be +Reports condition chains where a value range is checked which could be simplified to a single check. E.g. x > 2 && x < 4 could be simplified to x == 3 or arr.length == 0 || arr.length > 1 could be simplified to arr.length != 1.

New in 2019.1

diff --git a/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java b/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java index 6b9043a8d76f..dc46402a4bb4 100644 --- a/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java +++ b/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java @@ -87,6 +87,9 @@ public abstract class PsiAugmentProvider { try { PsiUtil.ensureValidType(type); } + catch (ProcessCanceledException e) { + throw e; + } catch (Throwable e) { throw PluginException.createByClass(e, provider.getClass()); } diff --git a/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBackedByPsiMethod.java b/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBackedByPsiMethod.java index a1acf2b859db..c0137fb89c25 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBackedByPsiMethod.java +++ b/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBackedByPsiMethod.java @@ -16,6 +16,7 @@ package com.intellij.psi.util; import com.intellij.diagnostic.PluginException; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; @@ -81,6 +82,9 @@ public class MethodSignatureBackedByPsiMethod extends MethodSignatureBase { try { substitutor.ensureValid(); } + catch (ProcessCanceledException e) { + throw e; + } catch (Throwable e) { throw PluginException.createByClass(e, method.getClass()); } diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocUtil.java b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocUtil.java index 0489d403ed8a..03e93ade227a 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocUtil.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocUtil.java @@ -144,7 +144,7 @@ public class JavaDocUtil { } @Nullable - private static PsiElement findReferencedMember(PsiClass aClass, String memberRefText, PsiElement context) { + private static PsiElement findReferencedMember(@NotNull PsiClass aClass, @NotNull String memberRefText, PsiElement context) { int parenthIndex = memberRefText.indexOf('('); if (parenthIndex < 0) { String name = memberRefText; @@ -197,7 +197,7 @@ public class JavaDocUtil { allMethods = aClass.findMethodsByName(name, true); } - PsiMethod[] methods = PsiDocMethodOrFieldRef.findMethods(methodSignature, context, name, allMethods); + PsiMethod[] methods = PsiDocMethodOrFieldRef.findMethods(methodSignature, aClass, name, allMethods); if (methods.length == 0) return null; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java index 562332543b8f..675d8ea011a8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerEx; +import com.intellij.psi.impl.PsiSuperMethodImplUtil; import com.intellij.psi.impl.source.Constants; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.resolve.JavaResolveUtil; @@ -44,9 +45,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; /** * @author mike @@ -204,26 +203,33 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo @NotNull public static PsiMethod[] findMethods(@Nullable MethodSignature methodSignature, - @Nullable PsiElement scope, + @NotNull PsiClass scope, @Nullable String name, @NotNull PsiMethod[] allMethods) { - List methods = new ArrayList<>(); - List exactMethods = new ArrayList<>(); + final PsiClass superClass = scope.getSuperClass(); + final PsiSubstitutor substitutor = superClass == null ? PsiSubstitutor.EMPTY : + TypeConversionUtil.getSuperClassSubstitutor(superClass, scope, PsiSubstitutor.EMPTY); - for (PsiMethod method : allMethods) { - if (!method.getName().equals(name) || - methodSignature != null && - !MethodSignatureUtil.areSignaturesErasureEqual(methodSignature, method.getSignature(PsiSubstitutor.EMPTY))) { + final List candidates = new ArrayList<>(Arrays.asList(allMethods)); + final Set filteredMethods = new HashSet<>(); + + for (PsiMethod method : candidates) { + if (filteredMethods.contains(method)) { continue; } - if (scope == null || scope.equals(method.getContainingClass())) exactMethods.add(method); + if (!method.getName().equals(name) || + methodSignature != null && !MethodSignatureUtil.areSignaturesErasureEqual(method.getSignature(substitutor), methodSignature)) { + filteredMethods.add(method); + } - methods.add(method); + PsiSuperMethodImplUtil.getHierarchicalMethodSignature(method) + .getSuperSignatures() + .forEach(signature -> filteredMethods.add(signature.getMethod())); } - List found = exactMethods.size() == 1 ? exactMethods : methods; - return found.toArray(PsiMethod.EMPTY_ARRAY); + candidates.removeAll(filteredMethods); + return candidates.toArray(PsiMethod.EMPTY_ARRAY); } @NotNull diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSwitchExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSwitchExpressionImpl.java index 0f328280b1c4..c86d740befb7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSwitchExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSwitchExpressionImpl.java @@ -46,6 +46,8 @@ public class PsiSwitchExpressionImpl extends PsiSwitchBlockImpl implements PsiSw resultTypes.add(resultExpressionType); } + if (resultTypes.isEmpty()) return null; + //If the result expressions all have the same type (which may be the null type), then that is the type of the switch expression. if (resultTypes.size() == 1) { return ContainerUtil.getFirstItem(resultTypes); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterBlocksInSameMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterBlocksInSameMethod.java index e28339b72fb9..702f28feefe3 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterBlocksInSameMethod.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterBlocksInSameMethod.java @@ -1,4 +1,4 @@ -// "Convert field to local variable in method 'IntelliJBugConvertToLocal'" "true" +// "Convert field to local variable in constructor" "true" import java.util.ArrayList; class ITest { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterFinalFieldIsCopy.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterFinalFieldIsCopy.java index ee74b9147a99..0405c3e3036f 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterFinalFieldIsCopy.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterFinalFieldIsCopy.java @@ -1,4 +1,4 @@ -// "Convert field to local variable in method 'Test'" "true" +// "Convert field to local variable in constructor" "true" class Test { public Test(String param) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterInitializer.java index 742386daff93..1f581d88f2f6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterInitializer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterInitializer.java @@ -1,4 +1,4 @@ -// "Convert to local" "true" +// "Convert field to local variable in initializer section" "true" class TestInitializer { { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethods.java index 3400ab952148..8a6d7b1f7802 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethods.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethods.java @@ -1,4 +1,4 @@ -// "Convert field to local variables in 2 methods" "true" +// "Convert to local" "true" class Test { int getFoo1() { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterSetterAfterSuperConstructorCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterSetterAfterSuperConstructorCall.java index c586623db745..ef019fc8a502 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterSetterAfterSuperConstructorCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterSetterAfterSuperConstructorCall.java @@ -1,4 +1,4 @@ -// "Convert field to local variable in method 'FieldCanBeLocalTest'" "true" +// "Convert field to local variable in constructor" "true" import javax.swing.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeBlocksInSameMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeBlocksInSameMethod.java index 36b9906265ce..b6bfe18e30e9 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeBlocksInSameMethod.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeBlocksInSameMethod.java @@ -1,4 +1,4 @@ -// "Convert field to local variable in method 'IntelliJBugConvertToLocal'" "true" +// "Convert field to local variable in constructor" "true" import java.util.ArrayList; class ITest { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeFinalFieldIsCopy.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeFinalFieldIsCopy.java index 6bf2affe92ba..063b1808fc58 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeFinalFieldIsCopy.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeFinalFieldIsCopy.java @@ -1,4 +1,4 @@ -// "Convert field to local variable in method 'Test'" "true" +// "Convert field to local variable in constructor" "true" class Test { private final String field; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeInitializer.java index 6cb02e618645..15ae086ba8cf 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeInitializer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeInitializer.java @@ -1,4 +1,4 @@ -// "Convert to local" "true" +// "Convert field to local variable in initializer section" "true" class TestInitializer { private boolean field; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethods.java index 8966a4769718..aefb1a497eee 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethods.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethods.java @@ -1,4 +1,4 @@ -// "Convert field to local variables in 2 methods" "true" +// "Convert to local" "true" class Test { private int myFoo; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethodsOnReadOnly.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethodsOnReadOnly.java index db61483db9ad..509aa695768e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethodsOnReadOnly.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethodsOnReadOnly.java @@ -1,4 +1,4 @@ -// "Convert to local" "false" +// "Fix all 'Field can be local' problems in file" "false" class MyClassTest { private boolean editable = false; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeSetterAfterSuperConstructorCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeSetterAfterSuperConstructorCall.java index 46cce76e3c23..49741a03cca9 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeSetterAfterSuperConstructorCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeSetterAfterSuperConstructorCall.java @@ -1,4 +1,4 @@ -// "Convert field to local variable in method 'FieldCanBeLocalTest'" "true" +// "Convert field to local variable in constructor" "true" import javax.swing.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeUsedInJavadoc.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeUsedInJavadoc.java index 65e8b00ac9d9..dbd56d5024bb 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeUsedInJavadoc.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeUsedInJavadoc.java @@ -1,4 +1,4 @@ -// "Convert to local" "false" +// "Fix all 'Field can be local' problems in file" "false" class TestFieldConversion { private static int someInt = 0; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterComments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterComments.java index a134d04c80f2..d75fc244ce24 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterComments.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterComments.java @@ -5,6 +5,8 @@ class Example { { //my comments here + //1 + //2 Runnable r = this::m } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforeComments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforeComments.java index e6373b741e74..879e93f83e2c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforeComments.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforeComments.java @@ -6,7 +6,10 @@ class Example { { Runnable r = () -> { //my comments here - m(); + m() + //1 + //2 + ; } } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterDefalutLabel.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterDefalutLabel.java new file mode 100644 index 000000000000..bda00aa5b0d4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterDefalutLabel.java @@ -0,0 +1,15 @@ +// "Copy 'switch' branch" "true" +class C { + void foo(int n) { + String s = ""; + switch (n) { + case 1: + case 2: + s = "x"; + break; + default: + s = "x"; + break; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterNonDefalutLabel.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterNonDefalutLabel.java new file mode 100644 index 000000000000..8f36af144694 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterNonDefalutLabel.java @@ -0,0 +1,15 @@ +// "Copy 'switch' branch" "true" +class C { + void foo(int n) { + String s = ""; + switch (n) { + default: + case 2: + s = "x"; + break; + case 1: + s = "x"; + break; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeDefalutLabel.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeDefalutLabel.java new file mode 100644 index 000000000000..d31de7e5a555 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeDefalutLabel.java @@ -0,0 +1,13 @@ +// "Copy 'switch' branch" "true" +class C { + void foo(int n) { + String s = ""; + switch (n) { + case 1: + default: + case 2: + s = "x"; + break; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeNonDefalutLabel.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeNonDefalutLabel.java new file mode 100644 index 000000000000..cd7e50f833c0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeNonDefalutLabel.java @@ -0,0 +1,13 @@ +// "Copy 'switch' branch" "true" +class C { + void foo(int n) { + String s = ""; + switch (n) { + case 1: + default: + case 2: + s = "x"; + break; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/filter/afterFilterFlatMapCollectionFilterMapCollect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/filter/afterFilterFlatMapCollectionFilterMapCollect.java index 354a6127d8e6..9aba26d77cfd 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/filter/afterFilterFlatMapCollectionFilterMapCollect.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/filter/afterFilterFlatMapCollectionFilterMapCollect.java @@ -4,7 +4,8 @@ import java.util.stream.Collectors; public class Main { public void test(List> nested) { - /*non-equal*//*empty*/ + /*non-equal*/ + /*empty*/ List result = nested.stream().filter(Objects::nonNull).flatMap(Collection::stream).filter(str -> str./*startswith*/startsWith("xyz")).map(String::trim).collect(Collectors.toList()); // 1 /*target is here*/ diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ComplexInitializer.java b/java/java-tests/testData/inspection/dataFlow/fixture/ComplexInitializer.java index c1857d1f5da1..4ad7c38c282e 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/ComplexInitializer.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ComplexInitializer.java @@ -63,7 +63,7 @@ class Constants { static native Object get(); } -class NotTooComplexInitializer { +class NotTooComplexInitializer { static { int i = 1; for(Object obj = Constants.get(); obj != Constants.C5; obj = Constants.get()) { @@ -84,7 +84,7 @@ class NotTooComplexInitializer { } } } -class NotTooComplexMergingInitializer { +class NotTooComplexMergingInitializer { static { foo(Constants.C1 == null, Constants.C2 == null, Constants.C3 == null, Constants.C4 == null, Constants.C5 == null, Constants.C6 == null, diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/EqualsInLoopNotTooComplex.java b/java/java-tests/testData/inspection/dataFlow/fixture/EqualsInLoopNotTooComplex.java index 6ed439c2022b..7f3c1421df40 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/EqualsInLoopNotTooComplex.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/EqualsInLoopNotTooComplex.java @@ -4,7 +4,7 @@ class Test { enum A {X, Y, Z}; List list1, list2; - void test(List tokens) { + void test(List tokens) { String t = "int"; A s = A.X; A l = A.X; diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ManyObjectEquals.java b/java/java-tests/testData/inspection/dataFlow/fixture/ManyObjectEquals.java index f55d980c445e..e43e3d23c7f7 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/ManyObjectEquals.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ManyObjectEquals.java @@ -191,7 +191,7 @@ public class ManyObjectEquals { private String test183; @Override - public boolean equals(Object o) { + public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ManyObjectEquals test = (ManyObjectEquals) o; diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/NestedScopeComplexity.java b/java/java-tests/testData/inspection/dataFlow/fixture/NestedScopeComplexity.java index 4bef90d1228d..f56cf68892a9 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/NestedScopeComplexity.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/NestedScopeComplexity.java @@ -30,7 +30,7 @@ class NestedScopeComplexity { static Object get() {return new Object();} - void test() { + void test() { int i = 1; for(Object obj = get(); obj != C100; obj = get()) { if (obj == C1) i = 2; diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpression.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpression.java index 10ff237cbb71..df6d8b91435a 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpression.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpression.java @@ -6,7 +6,7 @@ class C { case 2: break "b"; case 3: - break "a"; + break "a"; default: break ""; }; diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultFirst.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultFirst.java index 1b86bbbf4335..d0ce32d5bda4 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultFirst.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultFirst.java @@ -7,7 +7,7 @@ class C { case 2: break "b"; case 3: - break "a"; + break "a"; }; } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultLast.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultLast.java index 54d41a124d55..70f28327bfa1 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultLast.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultLast.java @@ -2,7 +2,7 @@ class C { void test(int n) { String s = switch (n) { case 1: - break "a"; + break "a"; case 2: break "b"; case 3: diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionSameComments.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionSameComments.java index 34035a0a5294..5f55aff25d39 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionSameComments.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionSameComments.java @@ -6,7 +6,7 @@ class C { case 2: break "b"; case 3: - break "a"; // same comment + break "a"; // same comment default: break ""; }; diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ExpressionParentheses.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ExpressionParentheses.java index 8e28a3e704b0..6379f8db99a0 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ExpressionParentheses.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ExpressionParentheses.java @@ -2,7 +2,7 @@ class C { String test(int i) { return switch (i) { case 0 -> null; - case 1 -> (null); + case 1 -> (null); default -> ""; }; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ReturnInStatement.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ReturnInStatement.java index af3138baf412..5c40a31a9026 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ReturnInStatement.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ReturnInStatement.java @@ -3,7 +3,7 @@ class C { return switch (n) { case 1 -> "A"; case 2 -> "B"; - case 3 -> "A"; + case 3 -> "A"; default -> ""; }; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleExpression.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleExpression.java index 1f60738ff1b2..e8bfc5d9abe8 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleExpression.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleExpression.java @@ -3,7 +3,7 @@ class C { String string = switch (n) { case 1 -> bar("A"); case 2 -> bar("B"); - case 3 -> bar("A"); + case 3 -> bar("A"); default -> ""; }; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleStatement.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleStatement.java index 948ef11901aa..f0d4cb5e9f8a 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleStatement.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleStatement.java @@ -3,7 +3,7 @@ class C { switch (n) { case 1 -> bar("A"); case 2 -> bar("B"); - case 3 -> bar("A"); + case 3 -> bar("A"); } } void bar(String s){} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/StatementParentheses.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/StatementParentheses.java index 427560266afa..af89b19389e3 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/StatementParentheses.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/StatementParentheses.java @@ -4,7 +4,7 @@ class C { case 0 ->{ return null; } - case 1 ->{ + case 1 ->{ return (null); } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInExpression.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInExpression.java index 9a1ecfc6f582..766681c413bd 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInExpression.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInExpression.java @@ -3,7 +3,7 @@ class C { String string = switch (n) { case 1 -> throw new IllegalArgumentException(); case 2 -> throw new IllegalStateException(); - case 3 -> throw new IllegalArgumentException(); + case 3 -> throw new IllegalArgumentException(); default -> ""; }; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInStatement.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInStatement.java index c5c80b5c5d84..a07b0c5d6d1d 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInStatement.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInStatement.java @@ -3,7 +3,7 @@ class C { switch (n) { case 1 -> throw new IllegalArgumentException(); case 2 -> throw new IllegalStateException(); - case 3 -> throw new IllegalArgumentException(); + case 3 -> throw new IllegalArgumentException(); } } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateAfterDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateAfterDefaultDelete.java index 3a7856ff93c0..42bce24c3bd4 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateAfterDefaultDelete.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateAfterDefaultDelete.java @@ -1,4 +1,4 @@ -// "Delete redundant 'switch' result expression" "GENERIC_ERROR_OR_WARNING" +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" class C { void foo(int n) { String s = switch (n) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDelete.java index d778394d1bcd..5520fd47b87b 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDelete.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDelete.java @@ -1,4 +1,4 @@ -// "Delete redundant 'switch' result expression" "GENERIC_ERROR_OR_WARNING" +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" class C { void foo(int n) { String s = switch (n) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDeleteAdjacent.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDeleteAdjacent.java index d778394d1bcd..5520fd47b87b 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDeleteAdjacent.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDeleteAdjacent.java @@ -1,4 +1,4 @@ -// "Delete redundant 'switch' result expression" "GENERIC_ERROR_OR_WARNING" +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" class C { void foo(int n) { String s = switch (n) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateAfterDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateAfterDefaultDelete.java index c0d30dd573a3..485f96a6d9e6 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateAfterDefaultDelete.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateAfterDefaultDelete.java @@ -1,4 +1,4 @@ -// "Delete redundant 'switch' result expression" "GENERIC_ERROR_OR_WARNING" +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" class C { void foo(int n) { String s = switch (n) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDelete.java index d0f4dde0acf3..a8545cf6b526 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDelete.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDelete.java @@ -1,4 +1,4 @@ -// "Delete redundant 'switch' result expression" "GENERIC_ERROR_OR_WARNING" +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" class C { void foo(int n) { String s = switch (n) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDeleteAdjacent.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDeleteAdjacent.java index dfd840b71ced..b50d3e58a94b 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDeleteAdjacent.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDeleteAdjacent.java @@ -1,4 +1,4 @@ -// "Delete redundant 'switch' result expression" "GENERIC_ERROR_OR_WARNING" +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" class C { void foo(int n) { String s = switch (n) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Assignment.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Assignment.java index 05e52111051d..0c17c5baed8c 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Assignment.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Assignment.java @@ -3,8 +3,8 @@ class C { String s; switch (n) { case 0: s = a(); break; - case 1: s = a(); break; - case 2: s = b(); break; + case 1: s = a(); break; + case 2: s = b(); break; default: s = b(); } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/BreakAndReturnUnderIf.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/BreakAndReturnUnderIf.java index ab22f4bbd344..ef3591c58f85 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/BreakAndReturnUnderIf.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/BreakAndReturnUnderIf.java @@ -14,7 +14,7 @@ class C { break; } case 3: - if(b) { + if(b) { return bar("A"); } else { break; diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ComplexBranches.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ComplexBranches.java index 1c33db404c4b..dd72ac35f3ad 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ComplexBranches.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ComplexBranches.java @@ -18,7 +18,7 @@ class C { bar("o"); break; case 3: - if(b) { + if(b) { bar("A"); } else { bar("z"); diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Continue.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Continue.java index 8b5f677511c1..596a5ced55ae 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Continue.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Continue.java @@ -9,7 +9,7 @@ class C { case 2: continue; case 3: - s += i; + s += i; continue; default: s += i; diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/DuplicateAfterDefault.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/DuplicateAfterDefault.java index 2e11cf08416c..7b4749a7b9de 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/DuplicateAfterDefault.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/DuplicateAfterDefault.java @@ -8,7 +8,7 @@ class C { bar("A"); break; case 1: - bar("A"); + bar("A"); break; } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/FallThroughToBreak.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/FallThroughToBreak.java index c4fcf393799b..344a1c5cf5fc 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/FallThroughToBreak.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/FallThroughToBreak.java @@ -6,10 +6,10 @@ class C { case 2: break; case 3: - bar("A"); + bar("A"); break; case 4: - bar("A"); + bar("A"); case 5: } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ManySimilarBranches.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ManySimilarBranches.java index a9837a19b235..cd99923bf985 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ManySimilarBranches.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ManySimilarBranches.java @@ -13,7 +13,7 @@ class C { case 6: bar("F");break; case 7: bar("G");break; case 8: bar("H");break; - case 9: bar("A");break; + case 9: bar("A");break; case 11: return Collections.singletonMap(k + 1, Collections.singletonList("A")); case 12: return Collections.singletonMap(k + 2, Collections.singletonList("B")); @@ -23,7 +23,7 @@ class C { case 16: return Collections.singletonMap(k + 6, Collections.singletonList("F")); case 17: return Collections.singletonMap(k + 7, Collections.singletonList("G")); case 18: return Collections.singletonMap(k + 8, Collections.singletonList("H")); - case 19: return Collections.singletonMap(k + 1, Collections.singletonList("A")); + case 19: return Collections.singletonMap(k + 1, Collections.singletonList("A")); case 21: synchronized (lock) { bar("A"); }break; case 22: synchronized (lock) { bar("B"); }break; @@ -33,7 +33,7 @@ class C { case 26: synchronized (lock) { bar("F"); }break; case 27: synchronized (lock) { bar("G"); }break; case 28: synchronized (lock) { bar("H"); }break; - case 29: synchronized (lock) { bar("A"); }break; + case 29: synchronized (lock) { bar("A"); }break; case 31: assert k == 1;break; case 32: assert k == 2;break; @@ -43,36 +43,36 @@ class C { case 36: assert k == 6;break; case 37: assert k == 7;break; case 38: assert k == 8;break; - case 39: assert k == 1;break; + case 39: assert k == 1;break; case 41: if (k > 0) bar("A"); else bar("B");break; - case 42: if (k > 0) bar("A"); else bar("B");break; - case 43: if (k > 0) bar("A"); else bar("B");break; - case 44: if (k > 0) bar("A"); else bar("B");break; - case 45: if (k > 0) bar("A"); else bar("B");break; - case 46: if (k > 0) bar("A"); else bar("B");break; - case 47: if (k > 0) bar("A"); else bar("B");break; - case 48: if (k > 0) bar("A"); else bar("B");break; - case 49: if (k > 0) bar("A"); else bar("B");break; - case 50: if (k > 0) bar("A"); else bar("B");break; - case 51: if (k > 0) bar("A"); else bar("B");break; - case 52: if (k > 0) bar("A"); else bar("B");break; - case 53: if (k > 0) bar("A"); else bar("B");break; - case 54: if (k > 0) bar("A"); else bar("B");break; - case 55: if (k > 0) bar("A"); else bar("B");break; - case 56: if (k > 0) bar("A"); else bar("B");break; - case 57: if (k > 0) bar("A"); else bar("B");break; - case 58: if (k > 0) bar("A"); else bar("B");break; - case 59: if (k > 0) bar("A"); else bar("B");break; - case 61: if (k > 0) bar("A"); else bar("B");break; - case 62: if (k > 0) bar("A"); else bar("B");break; - case 63: if (k > 0) bar("A"); else bar("B");break; - case 64: if (k > 0) bar("A"); else bar("B");break; - case 65: if (k > 0) bar("A"); else bar("B");break; - case 66: if (k > 0) bar("A"); else bar("B");break; - case 67: if (k > 0) bar("A"); else bar("B");break; - case 68: if (k > 0) bar("A"); else bar("B");break; - case 69: if (k > 0) bar("A"); else bar("B");break; + case 42: if (k > 0) bar("A"); else bar("B");break; + case 43: if (k > 0) bar("A"); else bar("B");break; + case 44: if (k > 0) bar("A"); else bar("B");break; + case 45: if (k > 0) bar("A"); else bar("B");break; + case 46: if (k > 0) bar("A"); else bar("B");break; + case 47: if (k > 0) bar("A"); else bar("B");break; + case 48: if (k > 0) bar("A"); else bar("B");break; + case 49: if (k > 0) bar("A"); else bar("B");break; + case 50: if (k > 0) bar("A"); else bar("B");break; + case 51: if (k > 0) bar("A"); else bar("B");break; + case 52: if (k > 0) bar("A"); else bar("B");break; + case 53: if (k > 0) bar("A"); else bar("B");break; + case 54: if (k > 0) bar("A"); else bar("B");break; + case 55: if (k > 0) bar("A"); else bar("B");break; + case 56: if (k > 0) bar("A"); else bar("B");break; + case 57: if (k > 0) bar("A"); else bar("B");break; + case 58: if (k > 0) bar("A"); else bar("B");break; + case 59: if (k > 0) bar("A"); else bar("B");break; + case 61: if (k > 0) bar("A"); else bar("B");break; + case 62: if (k > 0) bar("A"); else bar("B");break; + case 63: if (k > 0) bar("A"); else bar("B");break; + case 64: if (k > 0) bar("A"); else bar("B");break; + case 65: if (k > 0) bar("A"); else bar("B");break; + case 66: if (k > 0) bar("A"); else bar("B");break; + case 67: if (k > 0) bar("A"); else bar("B");break; + case 68: if (k > 0) bar("A"); else bar("B");break; + case 69: if (k > 0) bar("A"); else bar("B");break; } return Collections.emptyMap(); } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/MethodCallInReturn.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/MethodCallInReturn.java index 9b59d388f217..f304e97eb1e1 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/MethodCallInReturn.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/MethodCallInReturn.java @@ -7,10 +7,10 @@ enum T { return t.ordinal(); // comment 1 case B: - return t.ordinal(); + return t.ordinal(); case C: - return t.ordinal(); // comment 2 + return t.ordinal(); // comment 2 default: return 0; diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NoLastBreak.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NoLastBreak.java index ba5a9b985323..c80c007c19c6 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NoLastBreak.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NoLastBreak.java @@ -8,7 +8,7 @@ class C { bar("B"); break; case 3: - bar("A"); + bar("A"); } } void bar(String s){} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Parentheses.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Parentheses.java index 5ab056215787..566c8c3a01fc 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Parentheses.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Parentheses.java @@ -2,7 +2,7 @@ class C { String test(int i) { switch (i) { case 0: return null; - case 1: return (null); + case 1: return (null); } return ""; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Return.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Return.java index 279d6f216b5c..fc50633a268c 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Return.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Return.java @@ -6,7 +6,7 @@ class C { case 2: return "B"; case 3: - return "A"; + return "A"; } return ""; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ReturnWithComments.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ReturnWithComments.java index c0cea839f630..3ba67727c6f3 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ReturnWithComments.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ReturnWithComments.java @@ -13,24 +13,24 @@ enum C { return "A"; case LINE_COMMENT: // comment 1 - return "A"; + return "A"; case COMMENT_INSIDE_THE_CODE: - return /* comment 1 */"A"; + return /* comment 1 */"A"; case JAVADOC_COMMENT: /** comment 1 */ - return "A"; + return "A"; case COMMENT_WITH_NEW_LINES: /* comment 1 */ - return "A"; + return "A"; case EMPTY_COMMENTS_ARE_IGNORED: /* comment 1 */ // - return "A"; + return "A"; // comment 1 case COMMENT_RIGHT_BEFORE_A_CASE_IS_ATTACHED_TO_THAT_CASE: - return "A"; + return "A"; } return ""; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Simple.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Simple.java index 9ea8da8ad9c3..bb0c0275a31b 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Simple.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Simple.java @@ -8,7 +8,7 @@ class C { bar("B"); break; case 3: - bar("A"); + bar("A"); break; } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicates.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicates.java index a0f999f4ed9b..1f487f18d1e3 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicates.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicates.java @@ -8,10 +8,10 @@ class C { bar("B"); break; case 3: - bar("A"); + bar("A"); break; case 4: - bar("A"); + bar("A"); break; } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicatesDefault.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicatesDefault.java index d5497c91382f..05af5fedc09c 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicatesDefault.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicatesDefault.java @@ -2,13 +2,13 @@ class C { void foo(int n) { switch (n) { case 1: - bar("A"); + bar("A"); break; case 2: bar("B"); break; case 3: - bar("A"); + bar("A"); break; default: bar("A"); diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Throw.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Throw.java index 7021fa2adfd6..ac900caf94c8 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Throw.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Throw.java @@ -6,7 +6,7 @@ class C { case 2: throw new IllegalStateException("A"); case 3: - throw new IllegalArgumentException("A"); + throw new IllegalArgumentException("A"); } return ""; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/TwoCaseLabels.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/TwoCaseLabels.java index 3396a9fb2a53..09338258dd83 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/TwoCaseLabels.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/TwoCaseLabels.java @@ -6,7 +6,7 @@ class C { bar("A"); break; case 3: - bar("A"); + bar("A"); break; case 4: bar("B"); diff --git a/java/java-tests/testData/inspection/streamApiCallChains/afterEntrySetAdvanced.java b/java/java-tests/testData/inspection/streamApiCallChains/afterEntrySetAdvanced.java index 69f3fb0f63b1..ae5bbbabbbeb 100644 --- a/java/java-tests/testData/inspection/streamApiCallChains/afterEntrySetAdvanced.java +++ b/java/java-tests/testData/inspection/streamApiCallChains/afterEntrySetAdvanced.java @@ -34,7 +34,8 @@ class Scratch { } void testDecl(Map map) { - /*5*//*6*/ + /*5*/ + /*6*/ String res = map.values(/*0*/).stream().filter(val1 -> { /*1*/ return !val1./*2*/isEmpty(); diff --git a/java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.after.java b/java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.after.java new file mode 100644 index 000000000000..30c3a423b77b --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.after.java @@ -0,0 +1,8 @@ +class MyTest { + { + String temp = switch (0) { + default: + break ""; + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.java b/java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.java new file mode 100644 index 000000000000..a6b62ae1ee19 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.java @@ -0,0 +1,7 @@ +class MyTest { + { + switch (0) { + default: break ""; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/impl/SdkSetupNotificationTestBase.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/impl/SdkSetupNotificationTestBase.java index e233c3ab6a94..f97f17bf1960 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/impl/SdkSetupNotificationTestBase.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/impl/SdkSetupNotificationTestBase.java @@ -15,6 +15,7 @@ import com.intellij.psi.PsiFile; import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; import com.intellij.ui.EditorNotificationPanel; +import com.intellij.ui.EditorNotificationsImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -58,6 +59,7 @@ public abstract class SdkSetupNotificationTestBase extends JavaCodeInsightFixtur final PsiFile psiFile = myFixture.configureByText(name, text); final FileEditor[] editors = FileEditorManagerEx.getInstanceEx(getProject()).openFile(psiFile.getVirtualFile(), true); assertSize(1, editors); + EditorNotificationsImpl.completeAsyncTasks(); return editors[0].getUserData(SdkSetupNotificationProvider.KEY); } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchSuite.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchSuite.java index d15bb534e298..646408ff3b01 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchSuite.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchSuite.java @@ -5,6 +5,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Suite; /** + * Tests for {@link com.intellij.codeInspection.DuplicateBranchesInSwitchInspection} * @author Pavel.Dolgov */ @RunWith(Suite.class) diff --git a/java/java-tests/testSrc/com/intellij/java/index/IndexTest.groovy b/java/java-tests/testSrc/com/intellij/java/index/IndexTest.groovy index e429ae6f0868..9c87b7ff5e37 100644 --- a/java/java-tests/testSrc/com/intellij/java/index/IndexTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/index/IndexTest.groovy @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.java.index import com.intellij.ide.todo.TodoConfiguration @@ -154,7 +154,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { final VfsAwareMapIndexStorage indexStorage = new VfsAwareMapIndexStorage(storageFile, keyDescriptor, new EnumeratorStringDescriptor(), 16 * 1024, readOnly) return new StringIndex(testName, indexStorage, index, !readOnly) } - + private static PersistentHashMap> createMetaIndex(File metaIndexFile) throws IOException { return new PersistentHashMap>(metaIndexFile, new EnumeratorIntegerDescriptor(), new DataExternalizer>() { @Override @@ -250,7 +250,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { final VirtualFile vFile = psiFile.getVirtualFile() CodeStyleManager.getInstance(project).reformat(psiFile) - + PostprocessReformattingAspect.getInstance(project).doPostponedFormatting() PsiManager.getInstance(project).reloadFromDisk(psiFile) @@ -258,9 +258,9 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { def provider = PsiManager.getInstance(project).findViewProvider(vFile) def stubTree = ((PsiFileImpl)provider.getPsi(provider.getBaseLanguage())).getGreenStubTree() - + VfsUtil.saveText(vFile, "class Bar {}") - + assertNotNull(findClass("Foo")) } @@ -417,14 +417,14 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { GCUtil.tryGcSoftlyReachableObjects() assert ((PsiJavaFile)getPsiManager().findFile(vFile)).importList.node } - + void "test unknown file type in stubs" () { def vFile = myFixture.addFileToProject("Foo.java", "").virtualFile final Document document = FileDocumentManager.getInstance().getDocument(vFile) document.setText("class Foo {}") - PsiDocumentManager.getInstance(project).commitAllDocuments() + PsiDocumentManager.getInstance(project).commitAllDocuments() assert findClass("Foo") - + vFile.rename(null, "Foo1") assert !findClass("Foo") } @@ -553,12 +553,12 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile() def classEntry = new IdIndexEntry("class", true) def findValueProcessor = { file, value -> file != vFile } as FileBasedIndex.ValueProcessor - + def projectScope = GlobalSearchScope.projectScope(project) def result = FileBasedIndex.instance.processValues(IdIndexImpl.NAME, classEntry, null, findValueProcessor, projectScope) assertFalse(result) - + final Document document = FileDocumentManager.getInstance().getDocument(vFile) document.setText("") PsiDocumentManager.getInstance(project).commitAllDocuments() @@ -593,7 +593,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { void "test internalErrorOfStubProcessingInvalidatesIndex"() throws IOException { final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile() - + assertTrue(findClass("Foo") != null) runFindClassStubIndexQueryThatProducesInvalidResult("Foo") @@ -625,7 +625,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { return false } } - + try { StubIndex.instance. @@ -642,8 +642,8 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { catch (AssertionError ignored) { // stub mismatch } - - try { + + try { StubIndex.instance.processElements(JavaStubIndexKeys.CLASS_FQN, key, project, searchScope, PsiFile.class, processor) fail("Unexpected") @@ -893,7 +893,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { Document document = FileDocumentManager.getInstance().getDocument(srcFile.virtualFile) document.replaceString(0, document.getTextLength(), 'class B {}') assertNotNull(findClass('A')) - + ((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(project)).doCommitWithoutReparse(document) assertNull(findClass("A")) @@ -918,7 +918,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { assert findClass("Foo") } - + void "test read-only index has read-only storages"() { def index = createIndex(getTestName(false), new EnumeratorStringDescriptor(), true).getIndex() @@ -952,7 +952,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { eventList.add(new VFilePropertyChangeEvent(null, file, VirtualFile.PROP_NAME, filename, filename2, true)) eventList.add(new VFilePropertyChangeEvent(null, file, VirtualFile.PROP_NAME, filename2, filename, true)) eventList.add(new VFileDeleteEvent(null, file, true)) - eventList.add(new VFileCreateEvent(null, file.parent, filename, false, null, true, false)) + eventList.add(new VFileCreateEvent(null, file.parent, filename, false, null, null, true, false)) } IndexedFilesListener indexedFilesListener = ((FileBasedIndexImpl)FileBasedIndex.instance).changedFilesCollector @@ -972,18 +972,18 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { def projectScope = GlobalSearchScope.projectScope(project) assert !JavaOverridingMethodUtil.getOverridingMethodsIfCheapEnough(runnable.methods[0], projectScope, { true }).findFirst().present - assert StubIndex.instance.getElements(JavaStubIndexKeys.METHODS, 'run', project, projectScope, PsiMethod).empty + assert StubIndex.instance.getElements(JavaStubIndexKeys.METHODS, 'run', project, projectScope, PsiMethod).empty } void "test text todo indexing checks for cancellation"() { TodoPattern pattern = new TodoPattern("(x+x+)+y", TodoAttributesUtil.createDefault(), true) - + TodoPattern[] oldPatterns = TodoConfiguration.getInstance().getTodoPatterns() TodoPattern[] newPatterns = [pattern] TodoConfiguration.getInstance().setTodoPatterns(newPatterns) FileBasedIndex.instance.ensureUpToDate(TodoIndex.NAME, project, GlobalSearchScope.allScope(project)) myFixture.addFileToProject("Foo.txt", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") - + try { final CountDownLatch progressStarted = new CountDownLatch(1) final ProgressIndicatorBase progressIndicatorBase = new ProgressIndicatorBase() diff --git a/java/java-tests/testSrc/com/intellij/java/openapi/roots/impl/DirectoryIndexRestoreTest.java b/java/java-tests/testSrc/com/intellij/java/openapi/roots/impl/DirectoryIndexRestoreTest.java index b75f06133104..92ddc8cce51b 100644 --- a/java/java-tests/testSrc/com/intellij/java/openapi/roots/impl/DirectoryIndexRestoreTest.java +++ b/java/java-tests/testSrc/com/intellij/java/openapi/roots/impl/DirectoryIndexRestoreTest.java @@ -1,18 +1,4 @@ -/* - * 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. - */ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.java.openapi.roots.impl; import com.intellij.openapi.roots.ContentIterator; @@ -44,11 +30,11 @@ public class DirectoryIndexRestoreTest extends IdeaTestCase { LocalFileSystem fs = LocalFileSystem.getInstance(); File temp = createTempDirectory(); - myTempVFile = fs.findFileByIoFile(temp); + myTempVFile = fs.refreshAndFindFileByIoFile(temp); assertNotNull(myTempVFile); File root = new File(temp, "top/d1/d2/root"); assertTrue(root.mkdirs()); - VirtualFile rootVFile = fs.findFileByIoFile(root); + VirtualFile rootVFile = fs.refreshAndFindFileByIoFile(root); assertNotNull(rootVFile); VirtualFile moduleDir = createChildDirectory(rootVFile, "module"); diff --git a/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java b/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java index f3f95f3e859a..ba14779ceceb 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java +++ b/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java @@ -29,11 +29,11 @@ import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; public class DetectIndentAndTypeTest extends LightPlatformCodeInsightFixtureTestCase { private CodeStyleSettings mySettings; - private final String myText = "public class T {\n" + - "\tvoid run() {\n" + - "\t\tint t = 1 + 2;\n" + - "\t}\n" + - "}"; + private static final String myText = "public class T {\n" + + "\tvoid run() {\n" + + "\t\tint t = 1 + 2;\n" + + "\t}\n" + + "}"; @Override public void setUp() throws Exception { diff --git a/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/JavaAutoDetectIndentPerformanceTest.java b/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/JavaAutoDetectIndentPerformanceTest.java index 74e3c1417ea0..5e453bdee2c6 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/JavaAutoDetectIndentPerformanceTest.java +++ b/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/JavaAutoDetectIndentPerformanceTest.java @@ -42,9 +42,9 @@ public class JavaAutoDetectIndentPerformanceTest extends AbstractIndentAutoDetec public void testBigColdFile() { Ref ref = Ref.create(); - long fileLoadTime = TimeoutUtil.runAndGetExecutionTime(() -> configureByFile(getFileNameWithExtension())); + long fileLoadTime = TimeoutUtil.measureExecutionTime(() -> configureByFile(getFileNameWithExtension())); - long detectingTime = TimeoutUtil.runAndGetExecutionTime(() -> ref.set(detectIndentOptions())); + long detectingTime = TimeoutUtil.measureExecutionTime(() -> ref.set(detectIndentOptions())); double ratio = (double)detectingTime / fileLoadTime; if (ratio > 0.3) { TeamCityLogger.error("Detecting indent have taken too much time proportionally to file read time " + ratio); @@ -69,7 +69,7 @@ public class JavaAutoDetectIndentPerformanceTest extends AbstractIndentAutoDetec public void testBigOneLineFile() { configureByFile("oneLine.json"); - long time = TimeoutUtil.runAndGetExecutionTime(AbstractIndentAutoDetectionTest::detectIndentOptions); + long time = TimeoutUtil.measureExecutionTime(AbstractIndentAutoDetectionTest::detectIndentOptions); assertTrue(time < 40); } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceVariableTest.java index 73b2c338bea0..a5eee78cba49 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceVariableTest.java +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceVariableTest.java @@ -259,6 +259,10 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase { doTest(new MockIntroduceVariableHandler("temp", true, false, false, CommonClassNames.JAVA_LANG_STRING)); } + public void testFromSwitchStatementJava12Preview() { + doTest(new MockIntroduceVariableHandler("temp", true, false, false, CommonClassNames.JAVA_LANG_STRING)); + } + public void testDeclareTernary() { doTest(new MockIntroduceVariableHandler("temp", true, false, false, CommonClassNames.JAVA_LANG_STRING)); } diff --git a/java/jdkAnnotations/java/lang/annotations.xml b/java/jdkAnnotations/java/lang/annotations.xml index 601cb43aa126..85221f3da3f0 100644 --- a/java/jdkAnnotations/java/lang/annotations.xml +++ b/java/jdkAnnotations/java/lang/annotations.xml @@ -816,8 +816,5 @@ - - - diff --git a/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java b/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java index 77c0502b04a7..3c7716208b16 100644 --- a/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java +++ b/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java @@ -127,7 +127,8 @@ public class ExceptionWorker { else { virtualFiles = virtualFilesInContent; } - ToIntFunction columnFinder = elementMatcher == null ? null : new ExceptionColumnFinder(elementMatcher, myInfo.lineNumber - 1); + ToIntFunction columnFinder = + elementMatcher == null || myInfo.lineNumber < 0 ? null : new ExceptionColumnFinder(elementMatcher, myInfo.lineNumber - 1); HyperlinkInfo linkInfo = HyperlinkInfoFactory.getInstance().createMultipleFilesHyperlinkInfo(virtualFiles, myInfo.lineNumber - 1, myProject, columnFinder); Filter.Result result = new Filter.Result(highlightStartOffset, highlightEndOffset, linkInfo, attributes); diff --git a/java/testFramework/src/com/intellij/compiler/JavaInMemoryCompiler.java b/java/testFramework/src/com/intellij/compiler/JavaInMemoryCompiler.java new file mode 100644 index 000000000000..442d2a12c2f0 --- /dev/null +++ b/java/testFramework/src/com/intellij/compiler/JavaInMemoryCompiler.java @@ -0,0 +1,115 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.compiler; + +import org.intellij.lang.annotations.Language; + +import javax.tools.*; +import java.io.*; +import java.net.URI; +import java.util.*; + +/** + * @author Bas Leijdekkers + */ +public class JavaInMemoryCompiler { + + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + private final JavaMemFileManager myFileManager = new JavaMemFileManager(); + private final JavaCompiler myCompiler = ToolProvider.getSystemJavaCompiler(); + + public Map compile(String className, @Language("JAVA") String code) { + final DiagnosticCollector diagnostics = new DiagnosticCollector<>(); + final Iterable compilationUnits = Collections.singletonList(new JavaSourceFromString(className, code)); + final Iterable options = Arrays.asList("-g"); // generate debugging info. + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + final OutputStreamWriter out = new OutputStreamWriter(System.err); + final Boolean success = myCompiler.getTask(out, myFileManager, diagnostics, options, null, compilationUnits).call(); + + if (!success.booleanValue()) { + final StringWriter writer = new StringWriter(); + for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { + writer.write(diagnostic.getMessage(Locale.ENGLISH)); + writer.write(" on line " + diagnostic.getLineNumber()); + writer.write("\n"); + } + throw new RuntimeException(writer.toString()); + } + final List classFiles = myFileManager.getClassFiles(); + final Map result = new HashMap<>(2); + for (InMemoryClassFile classFile : classFiles) { + result.put(classFile.getClassName(), classFile.getBytes()); + } + return result; + } + + public static class JavaSourceFromString extends SimpleJavaFileObject { + + final String myCode; + + JavaSourceFromString(String className, String code) { + super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); + this.myCode = code; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return myCode; + } + } + + public static class InMemoryClassFile extends SimpleJavaFileObject { + + private final String myClassName; + ByteArrayOutputStream myOutputStream = new ByteArrayOutputStream(); + + public InMemoryClassFile(String className) { + super(URI.create("class:///" + className.replace('.', '/') + ".class"), Kind.CLASS); + myClassName = className; + } + + public String getClassName() { + return myClassName; + } + + public byte[] getBytes() { + return myOutputStream.toByteArray(); + } + + @Override + public OutputStream openOutputStream() { + myOutputStream.reset(); + return myOutputStream; + } + } + + public static class JavaMemFileManager extends ForwardingJavaFileManager { + + private final List myClassFiles = new ArrayList<>(2); + + public JavaMemFileManager() { + super(ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null)); + } + + @Override + public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) + throws IOException { + if (StandardLocation.CLASS_OUTPUT == location && JavaFileObject.Kind.CLASS == kind) { + final InMemoryClassFile file = new InMemoryClassFile(className); + myClassFiles.add(file); + return file; + } + else { + return super.getJavaFileForOutput(location, className, kind, sibling); + } + } + + public List getClassFiles() { + return myClassFiles; + } + + @Override + public ClassLoader getClassLoader(Location location) { + return null; + } + } +} \ No newline at end of file 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 f1e019603cd9..7d528091c55c 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy @@ -72,8 +72,6 @@ class CommunityLibraryLicenses { new LibraryLicense(name: "Apache Axis", libraryName: "axis-1.4", version: "1.4", license: "Apache 2.0", url: "http://ws.apache.org/axis/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.html"), - new LibraryLicense(name: "Apache Axis wstx-asl", libraryName: "wstx-asl", version: "1.4", license: "Apache 2.0", - url: "http://ws.apache.org/axis/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.html"), new LibraryLicense(name: "Apache Commons BeanUtils", libraryName: "commons-beanutils.jar", version: "1.6", license: "Apache 2.0", url: "http://commons.apache.org/beanutils/"), @@ -104,6 +102,8 @@ class CommunityLibraryLicenses { additionalLibraryNames: ["asm-capture"]), new LibraryLicense(name: "ASM Tools", libraryName: "asm-tools", license: "BSD", url: "http://asm.objectweb.org/", licenseUrl: "http://asm.objectweb.org/license.html"), + new LibraryLicense(name: "AssertJ fluent assertions", libraryName: "assertJ", version: "3.11.1", license: "Apache 2.0", + url: "http://joel-costigliola.github.io/assertj/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt"), new LibraryLicense(name: "Automaton", libraryName: "automaton", version: "1.12-1", license: "BSD", url: "http://www.brics.dk/automaton/", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php"), new LibraryLicense(name: "batik", libraryName: "batik", version: "1.9.1", license: "Apache 2.0", @@ -333,6 +333,8 @@ class CommunityLibraryLicenses { additionalLibraryNames: ["org.apache.maven.shared:maven-dependency-tree:1.2", "org.apache.maven.archetype:archetype-common:2.2"], version: "3.6.0", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0"), + new LibraryLicense(name: "Memory File System", libraryName: "memoryfilesystem", version: "1.3.0", license: "MIT", + url: "https://github.com/marschall/memoryfilesystem", licenseUrl: "http://opensource.org/licenses/MIT"), new LibraryLicense(name: "mercurial_prompthooks", attachedTo: "intellij.vcs.hg", version: "", license: "GPLv2 (used as hg extension called from hg executable)", url: "https://github.com/willemv/mercurial_prompthooks", diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy index cbbedb5c10ef..4e65f7462891 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy @@ -60,11 +60,11 @@ class LinuxDistributionBuilder extends OsSpecificDistributionBuilder { void buildArtifacts(String osSpecificDistPath) { buildContext.executeStep("Build Linux .tar.gz", BuildOptions.LINUX_ARTIFACTS_STEP) { if (customizer.buildTarGzWithoutBundledJre) { - buildTarGz(null, osSpecificDistPath) + buildTarGz(null, osSpecificDistPath, "-no-jdk") } def jreDirectoryPath = buildContext.bundledJreManager.extractLinuxJre() if (jreDirectoryPath != null) { - buildTarGz(jreDirectoryPath, osSpecificDistPath) + buildTarGz(jreDirectoryPath, osSpecificDistPath, buildContext.bundledJreManager.jreSuffix()) buildSnapPackage(jreDirectoryPath, osSpecificDistPath) } else { @@ -134,10 +134,8 @@ class LinuxDistributionBuilder extends OsSpecificDistributionBuilder { buildContext.ant.fixcrlf(file: "$unixDistPath/bin/Install-Linux-tar.txt", eol: "unix") } - private void buildTarGz(String jreDirectoryPath, String unixDistPath, String secondJreSuffix = null) { + private void buildTarGz(String jreDirectoryPath, String unixDistPath, String suffix) { def tarRoot = customizer.getRootDirectoryName(buildContext.applicationInfo, buildContext.buildNumber) - def suffix = secondJreSuffix - if (suffix == null) suffix = jreDirectoryPath != null ? buildContext.bundledJreManager.jreSuffix() : "-no-jdk" def tarPath = "$buildContext.paths.artifacts/${buildContext.productProperties.getBaseArtifactName(buildContext.applicationInfo, buildContext.buildNumber)}${suffix}.tar" def extraBins = customizer.extraExecutables def paths = [buildContext.paths.distAll, unixDistPath] diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/MacDistributionBuilder.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/MacDistributionBuilder.groovy index 26f2ef77f725..39fa5536d193 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/MacDistributionBuilder.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/MacDistributionBuilder.groovy @@ -272,12 +272,12 @@ class MacDistributionBuilder extends OsSpecificDistributionBuilder { buildContext.ant.fixcrlf(srcdir: "$target/bin", includes: "*.py", eol: "unix") } - private String buildMacZip(String macDistPath, String secondJreSuffix = null) { + private String buildMacZip(String macDistPath) { return buildContext.messages.block("Build zip archive for macOS") { def extraBins = customizer.extraExecutables def allPaths = [buildContext.paths.distAll, macDistPath] String zipRoot = getZipRoot(buildContext, customizer) - String suffix = secondJreSuffix == null ? buildContext.bundledJreManager.jreSuffix() : secondJreSuffix + String suffix = buildContext.bundledJreManager.jreSuffix() def targetPath = "$buildContext.paths.artifacts/${buildContext.productProperties.getBaseArtifactName(buildContext.applicationInfo, buildContext.buildNumber)}${suffix}.mac.zip" buildContext.messages.progress("Building zip archive for macOS") diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy index 4e171fbc30f7..d8603783ccde 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy @@ -79,8 +79,11 @@ class WindowsDistributionBuilder extends OsSpecificDistributionBuilder { buildWinLauncher(it, winDistPath) } customizer.copyAdditionalFiles(buildContext, winDistPath) - new File(winDistPath, "bin").listFiles(FileFilters.filesWithExtension("exe"))?.each { - buildContext.signExeFile(it.absolutePath) + List extensions = ["exe", "dll"] + for (String extension : extensions) { + new File(winDistPath, "bin").listFiles(FileFilters.filesWithExtension(extension))?.each { + buildContext.signExeFile(it.absolutePath) + } } return winDistPath } diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInServerOptions.java b/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInServerOptions.java index ea99ee870946..8e73024baeed 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInServerOptions.java +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInServerOptions.java @@ -1,12 +1,9 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.builtInWebServer; import com.intellij.notification.NotificationType; import com.intellij.openapi.application.ApplicationNamesInfo; -import com.intellij.openapi.components.PersistentStateComponent; -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.components.State; -import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.*; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.SimpleConfigurable; import com.intellij.openapi.util.Getter; @@ -27,7 +24,7 @@ import java.util.Collections; @State( name = "BuiltInServerOptions", - storages = @Storage(Storage.NOT_ROAMABLE_FILE) + storages = @Storage(StoragePathMacros.NOT_ROAMABLE_FILE) ) public class BuiltInServerOptions implements PersistentStateComponent, Getter { public static final int DEFAULT_PORT = 63342; diff --git a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt index e71b55f5c0df..7a1e7b4dbe43 100644 --- a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt +++ b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt @@ -440,7 +440,7 @@ internal val Storage.path: String get() = if (value.isEmpty()) file else value internal fun getEffectiveRoamingType(roamingType: RoamingType, collapsedPath: String): RoamingType { - if (roamingType != RoamingType.DISABLED && (collapsedPath == StoragePathMacros.WORKSPACE_FILE || collapsedPath == Storage.NOT_ROAMABLE_FILE || collapsedPath == StoragePathMacros.CACHE_FILE)) { + if (roamingType != RoamingType.DISABLED && (collapsedPath == StoragePathMacros.WORKSPACE_FILE || collapsedPath == StoragePathMacros.NOT_ROAMABLE_FILE || collapsedPath == StoragePathMacros.CACHE_FILE)) { return RoamingType.DISABLED } else { diff --git a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt index 83c8f1185c25..e0877d35c3e8 100644 --- a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt +++ b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt @@ -294,7 +294,7 @@ internal class ApplicationStoreTest { @Test fun `other xml file as not-roamable without explicit roaming`() = runBlocking { - @State(name = "A", storages = [(Storage(value = Storage.NOT_ROAMABLE_FILE))]) + @State(name = "A", storages = [(Storage(value = StoragePathMacros.NOT_ROAMABLE_FILE))]) class AOther : A() val component = AOther() @@ -303,7 +303,7 @@ internal class ApplicationStoreTest { saveStore() - assertThat(testAppConfig.resolve(Storage.NOT_ROAMABLE_FILE)).doesNotExist() + assertThat(testAppConfig.resolve(StoragePathMacros.NOT_ROAMABLE_FILE)).doesNotExist() } private suspend fun saveStore() { diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java index cee150857c9f..febb55431c8a 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java @@ -18,6 +18,7 @@ public class VFileCreateEvent extends VFileEvent { private final boolean myEmptyDirectory; @NotNull private final String myChildName; private final FileAttributes myAttributes; + private final String mySymlinkTarget; private VirtualFile myCreatedFile; public VFileCreateEvent(Object requestor, @@ -25,6 +26,7 @@ public class VFileCreateEvent extends VFileEvent { @NotNull String childName, boolean isDirectory, @Nullable("null means read from the created file") FileAttributes attributes, + @Nullable String symlinkTarget, boolean isFromRefresh, boolean isEmptyDirectory) { super(requestor, isFromRefresh); @@ -32,6 +34,7 @@ public class VFileCreateEvent extends VFileEvent { myParent = parent; myDirectory = isDirectory; myAttributes = attributes; + mySymlinkTarget = symlinkTarget; myEmptyDirectory = isEmptyDirectory; } @@ -61,6 +64,11 @@ public class VFileCreateEvent extends VFileEvent { return myAttributes; } + @Nullable + public String getSymlinkTarget() { + return mySymlinkTarget; + } + @NonNls @Override public String toString() { diff --git a/platform/core-api/src/com/intellij/psi/tree/IFileElementType.java b/platform/core-api/src/com/intellij/psi/tree/IFileElementType.java index af5f788cf723..474077f815d6 100644 --- a/platform/core-api/src/com/intellij/psi/tree/IFileElementType.java +++ b/platform/core-api/src/com/intellij/psi/tree/IFileElementType.java @@ -44,8 +44,12 @@ public class IFileElementType extends ILazyParseableElementType { @Nullable @Override public ASTNode parseContents(@NotNull final ASTNode chameleon) { - final PsiElement psi = chameleon.getPsi(); - assert psi != null : "Bad chameleon: " + chameleon; + PsiElement psi = chameleon.getPsi(); + if (psi == null) { + throw new AssertionError("Bad chameleon: " + chameleon + + " of type " + chameleon.getElementType() + + " in #" + chameleon.getElementType().getLanguage()); + } return doParseContents(chameleon, psi); } } diff --git a/platform/core-api/src/com/intellij/psi/util/CachedValue.java b/platform/core-api/src/com/intellij/psi/util/CachedValue.java index 5e20a88c892d..4972cea4a0f4 100644 --- a/platform/core-api/src/com/intellij/psi/util/CachedValue.java +++ b/platform/core-api/src/com/intellij/psi/util/CachedValue.java @@ -15,8 +15,8 @@ */ package com.intellij.psi.util; -import com.intellij.openapi.util.RecursionGuard; import com.intellij.openapi.util.Getter; +import com.intellij.openapi.util.RecursionGuard; import org.jetbrains.annotations.NotNull; /** @@ -37,7 +37,18 @@ import org.jetbrains.annotations.NotNull; * be run concurrently on more than one thread. Due to this and unpredictable garbage collection, * cached value providers shouldn't have side effects.

* - * Important note: if you store the CachedValue in a field or user data of some object {@code X}, then its {@link CachedValueProvider} + * Result equivalence: CachedValue might return a different result even if the previous one + * is still reachable and not garbage-collected, and dependencies haven't changed. Therefore CachedValue results + * should be equivalent and interchangeable if they're called multiple times. Examples: + *
    + *
  • If PSI declarations are cached, {@link #equals} or at least {@link com.intellij.psi.PsiManager#areElementsEquivalent} + * should hold for results from the same CachedValue.
  • + *
  • {@link com.intellij.psi.ResolveResult} objects should have equivalent {@code getElement()} values.
  • + *
  • Cached arrays or lists should have the same number of elements, and they also should be equivalent and come in the same order.
  • + *
  • If the result object's class has a meaningful {@link #equals} method, it should hold.
  • + *
+ * + * Context-independence: if you store the CachedValue in a field or user data of some object {@code X}, then its {@link CachedValueProvider} * may only depend on X and parts of global system state that don't change while {@code X} is alive and valid (e.g. application/project components/services). * Otherwise re-invoking the CachedValueProvider after invalidation would use outdated data and produce incorrect results, * possibly causing exceptions in places far, far away. In particular, the provider may not capture: diff --git a/platform/core-api/src/com/intellij/util/ExtensionInstantiator.java b/platform/core-api/src/com/intellij/util/ExtensionInstantiator.java index fbb27610a732..ee650961b563 100644 --- a/platform/core-api/src/com/intellij/util/ExtensionInstantiator.java +++ b/platform/core-api/src/com/intellij/util/ExtensionInstantiator.java @@ -2,10 +2,13 @@ package com.intellij.util; import com.intellij.diagnostic.PluginException; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.AbstractExtensionPointBean; import com.intellij.openapi.extensions.PluginDescriptor; import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.progress.ProcessCanceledException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.picocontainer.PicoContainer; @@ -36,9 +39,19 @@ public final class ExtensionInstantiator { try { return ReflectionUtil.newInstance(clazz, false); } + catch (ProcessCanceledException e) { + throw e; + } catch (Throwable e) { if (e.getCause() instanceof NoSuchMethodException) { - LOG.error(new PluginException("Bean extension class constructor must not have parameters: " + className, pluginId)); + PluginException exception = new PluginException("Bean extension class constructor must not have parameters: " + className, pluginId); + Application app = ApplicationManager.getApplication(); + if (app != null && app.isUnitTestMode()) { + LOG.error(exception); + } + else { + LOG.warn(exception); + } } else { throw new PluginException(e, pluginId); @@ -48,6 +61,9 @@ public final class ExtensionInstantiator { try { return AbstractExtensionPointBean.instantiate(clazz, picoContainer, true); } + catch (ProcessCanceledException e) { + throw e; + } catch (Throwable e) { throw new PluginException(e, pluginId); } 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 9cacd8a6fa62..4be558605aff 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 @@ -569,13 +569,14 @@ public class CoreProgressManager extends ProgressManager implements Disposable { startBackgroundNonStandardIndicatorsPing(); } - if (thisIndicator.isCanceled()) { - threadsUnderCanceledIndicator.add(currentThread); - oneOfTheIndicatorsIsCanceled = true; - } - else if (!oneOfTheIndicatorsIsCanceled) { - threadsUnderCanceledIndicator.remove(currentThread); - } + oneOfTheIndicatorsIsCanceled |= thisIndicator.isCanceled(); + } + + if (oneOfTheIndicatorsIsCanceled) { + threadsUnderCanceledIndicator.add(currentThread); + } + else { + threadsUnderCanceledIndicator.remove(currentThread); } updateShouldCheckCanceled(); diff --git a/platform/diff-api/src/com/intellij/diff/util/DiffUserDataKeys.java b/platform/diff-api/src/com/intellij/diff/util/DiffUserDataKeys.java index c42b19b4aa66..ad2fd2e83794 100644 --- a/platform/diff-api/src/com/intellij/diff/util/DiffUserDataKeys.java +++ b/platform/diff-api/src/com/intellij/diff/util/DiffUserDataKeys.java @@ -39,6 +39,9 @@ public interface DiffUserDataKeys { Key> SCROLL_TO_LINE_THREESIDE = Key.create("Diff.ScrollToLineThreeside"); Key HELP_ID = Key.create("Diff.HelpId"); + /** + * Used IN ADDITION to FORCE_READ_ONLY data key + */ Key FORCE_READ_ONLY_CONTENTS = Key.create("Diff.ForceReadOnlyContents"); // @@ -67,5 +70,10 @@ public interface DiffUserDataKeys { Key> CONTEXT_ACTIONS = Key.create("Diff.ContextActions"); Key DATA_PROVIDER = Key.create("Diff.DataProvider"); Key GO_TO_SOURCE_DISABLE = Key.create("Diff.GoToSourceDisable"); + + // + // DiffContext / DiffRequest / DiffContent + // + Key FORCE_READ_ONLY = Key.create("Diff.ForceReadOnly"); } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java b/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java index 515fdd7e3c00..66cd88b78bd6 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java @@ -15,20 +15,24 @@ */ package com.intellij.diff.actions; +import com.intellij.diff.DiffContentFactory; +import com.intellij.diff.DiffDialogHints; import com.intellij.diff.DiffManager; -import com.intellij.diff.requests.DiffRequest; +import com.intellij.diff.DiffRequestFactory; +import com.intellij.diff.actions.impl.MutableDiffRequestChain; +import com.intellij.diff.chains.DiffRequestChain; +import com.intellij.diff.contents.DiffContent; import com.intellij.openapi.actionSystem.ActionPlaces; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileWithoutContent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -abstract class BaseShowDiffAction extends AnAction implements DumbAware { +public abstract class BaseShowDiffAction extends DumbAwareAction { BaseShowDiffAction() { setEnabledInModalContext(true); } @@ -46,10 +50,10 @@ abstract class BaseShowDiffAction extends AnAction implements DumbAware { @Override public void actionPerformed(@NotNull AnActionEvent e) { Project project = e.getProject(); - DiffRequest request = getDiffRequest(e); - if (request == null) return; + DiffRequestChain chain = getDiffRequestChain(e); + if (chain == null) return; - DiffManager.getInstance().showDiff(project, request); + DiffManager.getInstance().showDiff(project, chain, DiffDialogHints.DEFAULT); } protected abstract boolean isAvailable(@NotNull AnActionEvent e); @@ -59,5 +63,24 @@ abstract class BaseShowDiffAction extends AnAction implements DumbAware { } @Nullable - protected abstract DiffRequest getDiffRequest(@NotNull AnActionEvent e); + protected abstract DiffRequestChain getDiffRequestChain(@NotNull AnActionEvent e); + + @NotNull + protected static MutableDiffRequestChain createMutableChainFromFiles(@Nullable Project project, + @NotNull VirtualFile file1, + @NotNull VirtualFile file2) { + DiffContentFactory contentFactory = DiffContentFactory.getInstance(); + DiffRequestFactory requestFactory = DiffRequestFactory.getInstance(); + + DiffContent content1 = contentFactory.create(project, file1); + DiffContent content2 = contentFactory.create(project, file2); + + MutableDiffRequestChain chain = new MutableDiffRequestChain(content1, content2); + + chain.setWindowTitle(requestFactory.getTitle(file1, file2)); + chain.setTitle1(requestFactory.getContentTitle(file1)); + chain.setTitle2(requestFactory.getContentTitle(file2)); + + return chain; + } } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java index b82c1fd5efa3..42b9bb517829 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java @@ -17,11 +17,12 @@ package com.intellij.diff.actions; import com.intellij.diff.DiffContentFactory; import com.intellij.diff.DiffRequestFactory; +import com.intellij.diff.actions.impl.MutableDiffRequestChain; +import com.intellij.diff.chains.DiffRequestChain; import com.intellij.diff.contents.DiffContent; import com.intellij.diff.contents.DocumentContent; import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.requests.DiffRequest; -import com.intellij.diff.requests.SimpleDiffRequest; import com.intellij.diff.tools.util.DiffDataKeys; import com.intellij.diff.util.DiffUserDataKeys; import com.intellij.diff.util.Side; @@ -77,7 +78,7 @@ public class CompareClipboardWithSelectionAction extends BaseShowDiffAction { @Nullable @Override - protected DiffRequest getDiffRequest(@NotNull AnActionEvent e) { + protected DiffRequestChain getDiffRequestChain(@NotNull AnActionEvent e) { Project project = e.getProject(); Editor editor = getEditor(e); FileType editorFileType = getEditorFileType(e); @@ -87,17 +88,15 @@ public class CompareClipboardWithSelectionAction extends BaseShowDiffAction { DocumentContent content2 = createContent(project, editor, editorFileType, selectedContent); DocumentContent content1 = DiffContentFactory.getInstance().createClipboardContent(project, content2); - String title1 = DiffBundle.message("diff.content.clipboard.content.title"); - String title2 = createContentTitle(editor); + MutableDiffRequestChain chain = new MutableDiffRequestChain(content1, content2); + chain.setWindowTitle(DiffBundle.message("diff.clipboard.vs.editor.dialog.title")); + chain.setTitle1(DiffBundle.message("diff.content.clipboard.content.title")); + chain.setTitle2(createContentTitle(editor)); - String title = DiffBundle.message("diff.clipboard.vs.editor.dialog.title"); + int currentLine = editor.getCaretModel().getLogicalPosition().line; + chain.putRequestUserData(DiffUserDataKeys.SCROLL_TO_LINE, Pair.create(Side.RIGHT, currentLine)); - SimpleDiffRequest request = new SimpleDiffRequest(title, content1, content2, title1, title2); - request.putUserData(DiffUserDataKeys.SCROLL_TO_LINE, Pair.create(Side.RIGHT, editor.getCaretModel().getLogicalPosition().line)); - if (editor.isViewer()) { - request.putUserData(DiffUserDataKeys.FORCE_READ_ONLY_CONTENTS, new boolean[]{false, true}); - } - return request; + return chain; } @NotNull @@ -124,6 +123,8 @@ public class CompareClipboardWithSelectionAction extends BaseShowDiffAction { content = DiffContentFactory.getInstance().createFragment(project, content, range); } + if (editor.isViewer()) content.putUserData(DiffUserDataKeys.FORCE_READ_ONLY, true); + return content; } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java index 5b38968f09e7..a64f91b7c0c2 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java @@ -3,11 +3,10 @@ */ package com.intellij.diff.actions; -import com.intellij.diff.DiffRequestFactory; +import com.intellij.diff.actions.impl.MutableDiffRequestChain; +import com.intellij.diff.chains.DiffRequestChain; import com.intellij.diff.contents.DiffContent; import com.intellij.diff.contents.DocumentContent; -import com.intellij.diff.requests.ContentDiffRequest; -import com.intellij.diff.requests.DiffRequest; import com.intellij.diff.util.DiffUserDataKeys; import com.intellij.diff.util.Side; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -70,24 +69,24 @@ public class CompareFileWithEditorAction extends BaseShowDiffAction { @Nullable @Override - protected DiffRequest getDiffRequest(@NotNull AnActionEvent e) { + protected DiffRequestChain getDiffRequestChain(@NotNull AnActionEvent e) { Project project = e.getProject(); VirtualFile selectedFile = getSelectedFile(e); VirtualFile currentFile = getEditingFile(e); - assert selectedFile != null && currentFile != null; - ContentDiffRequest request = DiffRequestFactory.getInstance().createFromFiles(project, selectedFile, currentFile); + MutableDiffRequestChain chain = createMutableChainFromFiles(project, selectedFile, currentFile); - DiffContent editorContent = request.getContents().get(1); + DiffContent editorContent = chain.getContent2(); if (editorContent instanceof DocumentContent) { Editor[] editors = EditorFactory.getInstance().getEditors(((DocumentContent)editorContent).getDocument()); if (editors.length != 0) { - request.putUserData(DiffUserDataKeys.SCROLL_TO_LINE, Pair.create(Side.RIGHT, editors[0].getCaretModel().getLogicalPosition().line)); + int currentLine = editors[0].getCaretModel().getLogicalPosition().line; + chain.putRequestUserData(DiffUserDataKeys.SCROLL_TO_LINE, Pair.create(Side.RIGHT, currentLine)); } } - return request; + return chain; } } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java index 1d1bc17ae61f..de4db8f746df 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java @@ -15,7 +15,8 @@ */ package com.intellij.diff.actions; -import com.intellij.diff.DiffRequestFactory; +import com.intellij.diff.chains.DiffRequestChain; +import com.intellij.diff.chains.SimpleDiffRequestChain; import com.intellij.diff.requests.DiffRequest; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.highlighter.ArchiveFileType; @@ -73,7 +74,7 @@ public class CompareFilesAction extends BaseShowDiffAction { @Override protected boolean isAvailable(@NotNull AnActionEvent e) { - DiffRequest request = e.getData(DIFF_REQUEST); + DiffRequest request = getDiffRequest(e); if (request != null) { return true; } @@ -95,12 +96,17 @@ public class CompareFilesAction extends BaseShowDiffAction { } @Nullable - @Override protected DiffRequest getDiffRequest(@NotNull AnActionEvent e) { + return e.getData(DIFF_REQUEST); + } + + @Nullable + @Override + protected DiffRequestChain getDiffRequestChain(@NotNull AnActionEvent e) { Project project = e.getProject(); - DiffRequest diffRequest = e.getData(DIFF_REQUEST); + DiffRequest diffRequest = getDiffRequest(e); if (diffRequest != null) { - return diffRequest; + return new SimpleDiffRequestChain(diffRequest); } VirtualFile file1; @@ -124,7 +130,7 @@ public class CompareFilesAction extends BaseShowDiffAction { if (type1 == Type.DIRECTORY || type2 == Type.DIRECTORY) FeatureUsageTracker.getInstance().triggerFeatureUsed("dir.diff"); if (type1 == Type.ARCHIVE || type2 == Type.ARCHIVE) FeatureUsageTracker.getInstance().triggerFeatureUsed("jar.diff"); - return DiffRequestFactory.getInstance().createFromFiles(project, file1, file2); + return createMutableChainFromFiles(project, file1, file2); } @Nullable diff --git a/platform/diff-impl/src/com/intellij/diff/actions/ShowBlankDiffWindowAction.kt b/platform/diff-impl/src/com/intellij/diff/actions/ShowBlankDiffWindowAction.kt index 7cc2a3462347..4ce5c5d15545 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/ShowBlankDiffWindowAction.kt +++ b/platform/diff-impl/src/com/intellij/diff/actions/ShowBlankDiffWindowAction.kt @@ -2,12 +2,10 @@ package com.intellij.diff.actions import com.intellij.diff.* -import com.intellij.diff.chains.DiffRequestChainBase -import com.intellij.diff.chains.DiffRequestProducer +import com.intellij.diff.actions.impl.MutableDiffRequestChain import com.intellij.diff.contents.DocumentContent import com.intellij.diff.contents.FileContent import com.intellij.diff.requests.DiffRequest -import com.intellij.diff.requests.SimpleDiffRequest import com.intellij.diff.tools.simple.SimpleDiffTool import com.intellij.diff.tools.util.DiffDataKeys import com.intellij.diff.tools.util.side.TwosideTextDiffViewer @@ -21,10 +19,9 @@ import com.intellij.openapi.editor.impl.EditorImpl import com.intellij.openapi.fileChooser.FileChooser import com.intellij.openapi.fileChooser.FileChooserDescriptor import com.intellij.openapi.fileEditor.impl.EditorWindow -import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.project.DumbAwareAction import com.intellij.openapi.project.Project -import com.intellij.openapi.util.UserDataHolder +import com.intellij.openapi.util.Key import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VirtualFile @@ -32,6 +29,8 @@ import java.awt.datatransfer.DataFlavor import java.awt.datatransfer.Transferable import java.io.File +private val BLANK_KEY = Key.create("Diff.BlankWindow") + class ShowBlankDiffWindowAction : DumbAwareAction() { init { isEnabledInModalContext = true @@ -49,51 +48,56 @@ class ShowBlankDiffWindowAction : DumbAwareAction() { val content1 = createEditableContent(project, StringUtil.notNullize(defaultText)) val content2 = createEditableContent(project, "") - val chain = BlankWindowDiffRequestChain(content1, content2) + val chain = MutableDiffRequestChain(content1, content2) chain.putUserData(DiffUserDataKeysEx.FORCE_DIFF_TOOL, SimpleDiffTool.INSTANCE) + chain.putUserData(BLANK_KEY, true) DiffManager.getInstance().showDiff(project, chain, DiffDialogHints.DEFAULT) } } internal class SwitchToBlankEditorAction : BlankActionBase() { - override fun isEnabled(viewer: TwosideTextDiffViewer, chain: BlankWindowDiffRequestChain, context: DiffContextEx, side: Side): Boolean { - val content = side.select(chain.content1, chain.content2) + override fun isEnabled(viewer: TwosideTextDiffViewer, helper: MutableDiffRequestChain.Helper, side: Side): Boolean { + val content = side.select(helper.chain.content1, helper.chain.content2) return content is FileContent } - override fun perform(viewer: TwosideTextDiffViewer, chain: BlankWindowDiffRequestChain, context: DiffContextEx, side: Side) { + override fun perform(viewer: TwosideTextDiffViewer, helper: MutableDiffRequestChain.Helper, side: Side) { val newContent = createEditableContent(viewer.project, "") - chain.setContent(newContent, side) + helper.setContent(newContent, side) - context.reloadDiffRequest() + helper.fireRequestUpdated() } } internal class SwitchToFileEditorAction : BlankActionBase() { - override fun isEnabled(viewer: TwosideTextDiffViewer, chain: BlankWindowDiffRequestChain, context: DiffContextEx, side: Side): Boolean { + override fun isEnabled(viewer: TwosideTextDiffViewer, helper: MutableDiffRequestChain.Helper, side: Side): Boolean { return true } - override fun perform(viewer: TwosideTextDiffViewer, chain: BlankWindowDiffRequestChain, context: DiffContextEx, side: Side) { + override fun perform(viewer: TwosideTextDiffViewer, helper: MutableDiffRequestChain.Helper, side: Side) { val descriptor = FileChooserDescriptor(true, false, false, false, false, false) descriptor.title = "Select File to Compare" descriptor.description = "" val file = FileChooser.chooseFile(descriptor, viewer.component, viewer.project, null) ?: return val newContent = createFileContent(viewer.project, file) ?: return - chain.setContent(newContent, side) + helper.setContent(newContent, side) - context.reloadDiffRequest() + helper.fireRequestUpdated() } } internal abstract class BlankActionBase : DumbAwareAction() { override fun update(e: AnActionEvent) { val viewer = e.getData(DiffDataKeys.DIFF_VIEWER) as? TwosideTextDiffViewer - val request = e.getData(DiffDataKeys.DIFF_REQUEST) as? BlankWindowDiffRequest - val context = e.getData(DiffDataKeys.DIFF_CONTEXT) as? DiffContextEx - if (viewer == null || request == null || context == null) { + val helper = MutableDiffRequestChain.createHelper(e.dataContext) + if (viewer == null || helper == null) { + e.presentation.isEnabledAndVisible = false + return + } + + if (helper.chain.getUserData(BLANK_KEY) != true) { e.presentation.isEnabledAndVisible = false return } @@ -105,45 +109,42 @@ internal abstract class BlankActionBase : DumbAwareAction() { return } - e.presentation.isEnabledAndVisible = isEnabled(viewer, request.chain, context, side) + e.presentation.isEnabledAndVisible = isEnabled(viewer, helper, side) } override fun actionPerformed(e: AnActionEvent) { val viewer = e.getData(DiffDataKeys.DIFF_VIEWER) as TwosideTextDiffViewer - val request = e.getData(DiffDataKeys.DIFF_REQUEST) as BlankWindowDiffRequest - val context = e.getData(DiffDataKeys.DIFF_CONTEXT) as DiffContextEx + val helper = MutableDiffRequestChain.createHelper(e.dataContext)!! val editor = e.getData(CommonDataKeys.EDITOR) val side = Side.fromValue(viewer.editors, editor)!! - perform(viewer, request.chain, context, side) + perform(viewer, helper, side) } protected abstract fun isEnabled(viewer: TwosideTextDiffViewer, - chain: BlankWindowDiffRequestChain, - context: DiffContextEx, + helper: MutableDiffRequestChain.Helper, side: Side): Boolean protected abstract fun perform(viewer: TwosideTextDiffViewer, - chain: BlankWindowDiffRequestChain, - context: DiffContextEx, + helper: MutableDiffRequestChain.Helper, side: Side) } class ShowBlankDiffWindowDiffExtension : DiffExtension() { override fun onViewerCreated(viewer: FrameDiffTool.DiffViewer, context: DiffContext, request: DiffRequest) { - if (request is BlankWindowDiffRequest && - context is DiffContextEx && - viewer is TwosideTextDiffViewer) { - DnDHandler(viewer, context, request.chain, Side.LEFT).install() - DnDHandler(viewer, context, request.chain, Side.RIGHT).install() + if (viewer is TwosideTextDiffViewer) { + val helper = MutableDiffRequestChain.createHelper(context, request) ?: return + if (helper.chain.getUserData(BLANK_KEY) == true) { + DnDHandler(viewer, helper, Side.LEFT).install() + DnDHandler(viewer, helper, Side.RIGHT).install() + } } } } private class DnDHandler(val viewer: TwosideTextDiffViewer, - val context: DiffContextEx, - val chain: BlankWindowDiffRequestChain, + val helper: MutableDiffRequestChain.Helper, val side: Side) : EditorDropHandler { fun install() { val editor = viewer.getEditor(side) as? EditorImpl ?: return @@ -156,7 +157,7 @@ private class DnDHandler(val viewer: TwosideTextDiffViewer, override fun handleDrop(t: Transferable, project: Project?, editorWindow: EditorWindow?) { val success = doHandleDnD(t) - if (success) context.reloadDiffRequest() + if (success) helper.fireRequestUpdated() } private fun doHandleDnD(transferable: Transferable): Boolean { @@ -164,14 +165,14 @@ private class DnDHandler(val viewer: TwosideTextDiffViewer, if (files != null) { if (files.size == 1) { val newContent = createFileContent(viewer.project, files[0]) ?: return false - chain.setContent(newContent, side) + helper.setContent(newContent, side) return true } if (files.size >= 2) { val newContent1 = createFileContent(viewer.project, files[0]) ?: return false val newContent2 = createFileContent(viewer.project, files[1]) ?: return false - chain.setContent(newContent1, Side.LEFT) - chain.setContent(newContent2, Side.RIGHT) + helper.setContent(newContent1, Side.LEFT) + helper.setContent(newContent2, Side.RIGHT) return true } } @@ -191,39 +192,3 @@ private fun createFileContent(project: Project?, file: File): DocumentContent? { private fun createFileContent(project: Project?, file: VirtualFile): DocumentContent? { return DiffContentFactory.getInstance().createDocument(project, file) } - -internal class BlankWindowDiffRequestChain(var content1: DocumentContent, var content2: DocumentContent) : DiffRequestChainBase() { - var title1: String? = getTitleFor(content1) - var title2: String? = getTitleFor(content2) - - override fun getRequests(): List { - return listOf(object : DiffRequestProducer { - override fun getName(): String { - return "Change" - } - - override fun process(context: UserDataHolder, indicator: ProgressIndicator): DiffRequest { - return BlankWindowDiffRequest(this@BlankWindowDiffRequestChain) - } - }) - } - - fun setContent(newContent: DocumentContent, side: Side) { - val title = getTitleFor(newContent) - - if (side.isLeft) { - content1 = newContent - title1 = title - } - else { - content2 = newContent - title2 = title - } - } - - private fun getTitleFor(content: DocumentContent) = - if (content is FileContent) DiffRequestFactory.getInstance().getContentTitle(content.file) else null -} - -private class BlankWindowDiffRequest internal constructor(val chain: BlankWindowDiffRequestChain) - : SimpleDiffRequest(null, chain.content1, chain.content2, chain.title1, chain.title2) diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt b/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt new file mode 100644 index 000000000000..1c44e65bca66 --- /dev/null +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt @@ -0,0 +1,114 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.diff.actions.impl + +import com.intellij.diff.DiffContext +import com.intellij.diff.DiffContextEx +import com.intellij.diff.DiffRequestFactory +import com.intellij.diff.chains.DiffRequestChainBase +import com.intellij.diff.chains.DiffRequestProducer +import com.intellij.diff.contents.DiffContent +import com.intellij.diff.contents.FileContent +import com.intellij.diff.requests.DiffRequest +import com.intellij.diff.requests.SimpleDiffRequest +import com.intellij.diff.tools.util.DiffDataKeys +import com.intellij.diff.util.Side +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.DumbAwareAction +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.UserDataHolder + +class MutableDiffRequestChain(var content1: DiffContent, var content2: DiffContent) : DiffRequestChainBase() { + private val requestUserData: MutableList, Any>> = mutableListOf() + var windowTitle: String? = null + var title1: String? = getTitleFor(content1) + var title2: String? = getTitleFor(content2) + + fun putRequestUserData(key: Key, value: T) { + requestUserData.add(Pair(key, value)) + } + + override fun getRequests(): List { + return listOf(object : DiffRequestProducer { + override fun getName(): String { + return "Change" + } + + override fun process(context: UserDataHolder, indicator: ProgressIndicator): DiffRequest { + val request = MutableChainDiffRequest(this@MutableDiffRequestChain) + for (it in requestUserData) { + @Suppress("UNCHECKED_CAST") + request.putUserData(it.first as Key, it.second) + } + return request + } + }) + } + + companion object { + fun createHelper(context: DiffContext, request: DiffRequest): Helper? { + if (context !is DiffContextEx || request !is MutableChainDiffRequest) return null + return Helper(request.chain, context) + } + + fun createHelper(dataContext: DataContext): Helper? { + val context = dataContext.getData(DiffDataKeys.DIFF_CONTEXT) as? DiffContextEx ?: return null + val request = dataContext.getData(DiffDataKeys.DIFF_REQUEST) as? MutableChainDiffRequest ?: return null + return Helper(request.chain, context) + } + } + + data class Helper(val chain: MutableDiffRequestChain, val context: DiffContextEx) { + fun setContent(newContent: DiffContent, side: Side) { + setContent(newContent, getTitleFor(newContent), side) + } + + fun setContent(newContent: DiffContent, title: String?, side: Side) { + if (side.isLeft) { + chain.content1 = newContent + chain.title1 = title + } + else { + chain.content2 = newContent + chain.title2 = title + } + } + + fun fireRequestUpdated() { + chain.requestUserData.clear() + context.reloadDiffRequest() + } + } +} + +internal class SwapDiffSidesAction : DumbAwareAction() { + override fun update(e: AnActionEvent) { + val helper = MutableDiffRequestChain.createHelper(e.dataContext) + if (helper == null) { + e.presentation.isEnabledAndVisible = false + return + } + + e.presentation.isEnabledAndVisible = true + } + + override fun actionPerformed(e: AnActionEvent) { + val helper = MutableDiffRequestChain.createHelper(e.dataContext)!! + + val oldContent1 = helper.chain.content1 + val oldContent2 = helper.chain.content2 + val oldTitle1 = helper.chain.title1 + val oldTitle2 = helper.chain.title2 + + helper.setContent(oldContent1, oldTitle1, Side.RIGHT) + helper.setContent(oldContent2, oldTitle2, Side.LEFT) + helper.fireRequestUpdated() + } +} + +private fun getTitleFor(content: DiffContent) = + if (content is FileContent) DiffRequestFactory.getInstance().getContentTitle(content.file) else null + +private class MutableChainDiffRequest(val chain: MutableDiffRequestChain) + : SimpleDiffRequest(chain.windowTitle, chain.content1, chain.content2, chain.title1, chain.title2) diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/MergeResolveUtil.kt b/platform/diff-impl/src/com/intellij/diff/comparison/MergeResolveUtil.kt index 53d30b6b8cad..742098f49e5e 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/MergeResolveUtil.kt +++ b/platform/diff-impl/src/com/intellij/diff/comparison/MergeResolveUtil.kt @@ -252,7 +252,7 @@ private class GreedyHelper(val leftText: CharSequence, val baseText: CharSequenc } // we faced conflicting insertions - resolve failed - return null; + return null } return newContent diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.kt b/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.kt index 6f61a0fb608f..a9e895af8992 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.kt +++ b/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.kt @@ -192,10 +192,10 @@ fun expandWhitespacesBackward(text1: CharSequence, text2: CharSequence, text3: C } -fun trimExpandRange(start1: Int, start2: Int, end1: Int, end2: Int, - equals: (Int, Int) -> Boolean, - ignored1: (Int) -> Boolean, - ignored2: (Int) -> Boolean): Range { +fun trimExpandRange(start1: Int, start2: Int, end1: Int, end2: Int, + equals: (Int, Int) -> Boolean, + ignored1: (Int) -> Boolean, + ignored2: (Int) -> Boolean): Range { return trimExpand(start1, start2, end1, end2, { index1, index2 -> equals(index1, index2) }, { index -> ignored1(index) }, diff --git a/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt b/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt index 8ee18999d439..27147d5caf7b 100644 --- a/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt +++ b/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt @@ -50,14 +50,14 @@ class DiffSettingsHolder : PersistentStateComponent { fun getSettings(place: String?): DiffSettings { val placeKey = place ?: DiffPlaces.DEFAULT - val placeSettings = myState.PLACES_MAP.getOrPut(placeKey, { defaultPlaceSettings(placeKey) }) + val placeSettings = myState.PLACES_MAP.getOrPut(placeKey) { defaultPlaceSettings(placeKey) } return DiffSettings(myState.SHARED_SETTINGS, placeSettings) } private fun copyStateWithoutDefaults(): State { val result = State() result.SHARED_SETTINGS = myState.SHARED_SETTINGS - result.PLACES_MAP = DiffUtil.trimDefaultValues(myState.PLACES_MAP, { defaultPlaceSettings(it) }) + result.PLACES_MAP = DiffUtil.trimDefaultValues(myState.PLACES_MAP) { defaultPlaceSettings(it) } return result } diff --git a/platform/diff-impl/src/com/intellij/diff/settings/DiffSettingsConfigurable.java b/platform/diff-impl/src/com/intellij/diff/settings/DiffSettingsConfigurable.java index 280248344a22..ce1075282c8e 100644 --- a/platform/diff-impl/src/com/intellij/diff/settings/DiffSettingsConfigurable.java +++ b/platform/diff-impl/src/com/intellij/diff/settings/DiffSettingsConfigurable.java @@ -15,7 +15,6 @@ */ package com.intellij.diff.settings; -import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; diff --git a/platform/diff-impl/src/com/intellij/diff/settings/ExternalDiffSettingsConfigurable.java b/platform/diff-impl/src/com/intellij/diff/settings/ExternalDiffSettingsConfigurable.java index 225275bfe589..7f317b653eca 100644 --- a/platform/diff-impl/src/com/intellij/diff/settings/ExternalDiffSettingsConfigurable.java +++ b/platform/diff-impl/src/com/intellij/diff/settings/ExternalDiffSettingsConfigurable.java @@ -15,7 +15,6 @@ */ package com.intellij.diff.settings; -import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffTool.java b/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffTool.java index 8093f89a30f9..33d0a0e55bb0 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffTool.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffTool.java @@ -17,7 +17,6 @@ package com.intellij.diff.tools.binary; import com.intellij.diff.DiffContext; import com.intellij.diff.FrameDiffTool; -import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.requests.DiffRequest; import org.jetbrains.annotations.NotNull; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedEditorRangeHighlighter.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedEditorRangeHighlighter.java index d4f577d4e2f2..fab1673016e3 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedEditorRangeHighlighter.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedEditorRangeHighlighter.java @@ -16,7 +16,6 @@ package com.intellij.diff.tools.fragmented; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.ex.MarkupModelEx; import com.intellij.openapi.editor.ex.RangeHighlighterEx; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/FoldingModelSupport.java b/platform/diff-impl/src/com/intellij/diff/tools/util/FoldingModelSupport.java index ba7aba65dfa0..57378982faad 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/FoldingModelSupport.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/FoldingModelSupport.java @@ -320,7 +320,7 @@ public class FoldingModelSupport { private class MyFoldingListener implements FoldingListener { private final int myIndex; - @NotNull Set myModifiedRegions = new HashSet<>(); + @NotNull private final Set myModifiedRegions = new HashSet<>(); MyFoldingListener(int index) { myIndex = index; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/ThreeDiffSplitter.java b/platform/diff-impl/src/com/intellij/diff/tools/util/ThreeDiffSplitter.java index 47bca5da5f15..fb2922df74d4 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/ThreeDiffSplitter.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/ThreeDiffSplitter.java @@ -160,7 +160,7 @@ public class ThreeDiffSplitter extends JPanel { Divider(@NotNull Side side) { mySide = side; - enableEvents(MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK); + enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)); } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt index 4c9990156d0e..51b43f73158f 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt @@ -144,14 +144,14 @@ class TextDiffSettingsHolder : PersistentStateComponent contents = request.getContents(); + int contentCount = contents.size(); boolean[] result = new boolean[contentCount]; - if (DiffUtil.isUserDataFlagSet(DiffUserDataKeys.FORCE_READ_ONLY, request, context)) { - Arrays.fill(result, true); - return result; + boolean[] data = request.getUserData(DiffUserDataKeys.FORCE_READ_ONLY_CONTENTS); + if (data != null && data.length != contentCount) { + LOG.warn("Invalid FORCE_READ_ONLY_CONTENTS key value: " + request); + data = null; } - boolean[] data = request.getUserData(DiffUserDataKeys.FORCE_READ_ONLY_CONTENTS); - if (data != null && data.length == contentCount) { - return data; + for (int i = 0; i < contents.size(); i++) { + if (isUserDataFlagSet(DiffUserDataKeys.FORCE_READ_ONLY, contents.get(i), request, context) || + data != null && data[i]) { + result[i] = true; + } } return result; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideTextDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideTextDiffViewer.java index 5f04ce0ab025..6b634703484c 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideTextDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideTextDiffViewer.java @@ -53,8 +53,7 @@ public abstract class ThreesideTextDiffViewer extends ThreesideDiffViewer myEditors; @NotNull private final List myEditableEditors; - @NotNull private final MyVisibleAreaListener myVisibleAreaListener1 = new MyVisibleAreaListener(Side.LEFT); - @NotNull private final MyVisibleAreaListener myVisibleAreaListener2 = new MyVisibleAreaListener(Side.RIGHT); + @NotNull private final MyVisibleAreaListener myVisibleAreaListener = new MyVisibleAreaListener(); @Nullable protected ThreesideSyncScrollSupport mySyncScrollSupport; @NotNull protected final SetEditorSettingsAction myEditorSettingsAction; @@ -127,11 +126,9 @@ public abstract class ThreesideTextDiffViewer extends ThreesideDiffViewer Unit): Unit = doTest(TestType.CHAR_SMART, f) internal fun splitter(squash: Boolean = false, trim: Boolean = false, f: TestBuilder.() -> Unit) { - doTest(TestType.SPLITTER, { + doTest(TestType.SPLITTER) { postprocess(squash, trim) f() - }) + } } private fun doTest(type: TestType, f: TestBuilder.() -> Unit) { diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt index 95f6261c15dc..6f46cf110a89 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt @@ -323,13 +323,13 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { } fun `test prefer smaller amount of chunks`() { - lines() { + lines { ("X_A_X_Y_" - "X_Y_") ("-_-_ _ _" - " _ _").default() testAll() } - lines() { + lines { (" __x___y" - "__y") ("-**-*__ " - "__ ").default() default(del(0, 0, 3)) @@ -387,7 +387,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { testAll() } - splitter() { + splitter { ("M===_X===_Y===" - " Y===_X===_N") // TODO: default(mod(0, 0, 1, 1), mod(2, 2, 1, 1)) default(mod(0, 0, 1, 1), mod(1, 1, 1, 1), mod(2, 2, 1, 1)) @@ -413,7 +413,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { } fun `test trim changed blocks after second step correction`() { - lines() { + lines { ("====}_==== }_Y_====}" - "====}_Y_====}") (" _------_ _ " - " _ _ ").default() // result after second step correction (" _ _-_-----" - " _-_ ").ignore() // result looks strange because of 'diff.unimportant.line.char.count' @@ -430,20 +430,20 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { } fun `test ignore whitespace policy does not applies two-step correction`() { - lines() { + lines { ("1_ _ 1" - " 1") ("-_-_ " - " ").default() (" _-_---" - " ").trim() testAll() } - lines() { + lines { (" 1_ _1" - " 1") (" _-_-" - " ").default() testAll() } - lines() { + lines { ("X_ Y_X" - "Y ") ("-_--_-" - "--").default() ("-_ _-" - " ").trim() @@ -466,7 +466,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { testAll() } - lines() { + lines { ("X_X __Y" - "X__Z") (" _--__-" - " __-").default() ("-_ __-" - " __-").trim() diff --git a/platform/diff-impl/tests/com/intellij/diff/contents/FragmentContentTest.kt b/platform/diff-impl/tests/com/intellij/diff/contents/FragmentContentTest.kt index 62d155138e0b..52f66af68b2a 100644 --- a/platform/diff-impl/tests/com/intellij/diff/contents/FragmentContentTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/contents/FragmentContentTest.kt @@ -83,22 +83,22 @@ class FragmentContentTest : HeavyDiffTestCase() { fun testRemoveOriginalFragment() { assertTrue(fragment.isWritable) - replaceString(document, 2, 8, ""); - assertEquals("0189", document.text); + replaceString(document, 2, 8, "") + assertEquals("0189", document.text) assertEquals("Invalid selection range", fragment.text) assertFalse(fragment.isWritable) } fun testRemoveListeners() { - replaceString(fragment, 0, 1, "x"); - assertEquals("012x456789", document.text); + replaceString(fragment, 0, 1, "x") + assertEquals("012x456789", document.text) fragmentContent.onAssigned(false) - replaceString(fragment, 0, 1, "3"); - assertEquals("012x456789", document.text); - replaceString(document, 3, 4, "y"); - assertEquals("012y456789", document.text); - assertEquals("3456", fragment.text); + replaceString(fragment, 0, 1, "3") + assertEquals("012x456789", document.text) + replaceString(document, 3, 4, "y") + assertEquals("012y456789", document.text) + assertEquals("3456", fragment.text) fragmentContent.onAssigned(true) } diff --git a/platform/diff-impl/tests/com/intellij/diff/merge/MergeAutoTest.kt b/platform/diff-impl/tests/com/intellij/diff/merge/MergeAutoTest.kt index 5f8e8b6d4883..c5dab5c90eb3 100644 --- a/platform/diff-impl/tests/com/intellij/diff/merge/MergeAutoTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/merge/MergeAutoTest.kt @@ -57,7 +57,7 @@ class MergeAutoTest : MergeTestBase() { } } - private fun TestBuilder.doApply(): Unit { + private fun TestBuilder.doApply() { val index = RNG.nextInt(changes.size) val change = changes[index] @@ -67,7 +67,7 @@ class MergeAutoTest : MergeTestBase() { command(change) { viewer.replaceChange(change, side, modifier) } } - private fun TestBuilder.doIgnore(): Unit { + private fun TestBuilder.doIgnore() { val index = RNG.nextInt(changes.size) val change = changes[index] @@ -77,18 +77,18 @@ class MergeAutoTest : MergeTestBase() { command(change) { viewer.ignoreChange(change, side, modifier) } } - private fun TestBuilder.doTryResolve(): Unit { + private fun TestBuilder.doTryResolve() { val index = RNG.nextInt(changes.size) val change = changes[index] command(change) { viewer.resolveChangeAutomatically(change, ThreeSide.BASE) } } - private fun TestBuilder.doModifyText(): Unit { + private fun TestBuilder.doModifyText() { val length = document.textLength - var index1: Int = 0 - var index2: Int = 0 + var index1 = 0 + var index2 = 0 if (length != 0) { index1 = RNG.nextInt(length) index2 = index1 + RNG.nextInt(length - index1) diff --git a/platform/diff-impl/tests/com/intellij/diff/merge/MergeTestBase.kt b/platform/diff-impl/tests/com/intellij/diff/merge/MergeTestBase.kt index 5712ca0a6e0b..3ce619a2f21b 100644 --- a/platform/diff-impl/tests/com/intellij/diff/merge/MergeTestBase.kt +++ b/platform/diff-impl/tests/com/intellij/diff/merge/MergeTestBase.kt @@ -111,17 +111,17 @@ abstract class MergeTestBase : HeavyDiffTestCase() { // Modification // - fun command(affected: TextMergeChange, f: () -> Unit): Unit { + fun command(affected: TextMergeChange, f: () -> Unit) { command(listOf(affected), f) } - fun command(affected: List? = null, f: () -> Unit): Unit { + fun command(affected: List? = null, f: () -> Unit) { viewer.executeMergeCommand(null, affected, f) UIUtil.dispatchAllInvocationEvents() } - fun write(f: () -> Unit): Unit { - ApplicationManager.getApplication().runWriteAction({ CommandProcessor.getInstance().executeCommand(project, f, null, null) }) + fun write(f: () -> Unit) { + ApplicationManager.getApplication().runWriteAction { CommandProcessor.getInstance().executeCommand(project, f, null, null) } } fun Int.ignore(side: Side, modifier: Boolean = false) { @@ -334,8 +334,7 @@ abstract class MergeTestBase : HeavyDiffTestCase() { operator fun Int.not(): LineColHelper = LineColHelper(this) operator fun LineColHelper.minus(col: Int): LineCol = LineCol(this.line, col) - inner class LineColHelper(val line: Int) { - } + inner class LineColHelper(val line: Int) inner class LineCol(val line: Int, val col: Int) { fun toOffset(): Int = editor.document.getLineStartOffset(line) + col @@ -384,7 +383,7 @@ abstract class MergeTestBase : HeavyDiffTestCase() { } private fun recordChangeState(viewer: MyThreesideViewer, change: TextMergeChange): ChangeState { - val document = viewer.editor.document; + val document = viewer.editor.document val content = DiffUtil.getLinesContent(document, change.startLine, change.endLine) val resolved = diff --git a/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilderTest.kt b/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilderTest.kt index 6503c4e82c43..7596b94bce20 100644 --- a/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilderTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilderTest.kt @@ -236,9 +236,9 @@ class UnifiedFragmentBuilderTest : DiffTestCase() { builder.exec() - val lineCount1 = input1.count({ it == '_' }) + 1 - val lineCount2 = input2.count({ it == '_' }) + 1 - val resultLineCount = result.count({ it == '_' }) + 1 + val lineCount1 = input1.count { it == '_' } + 1 + val lineCount2 = input2.count { it == '_' } + 1 + val resultLineCount = result.count { it == '_' } + 1 val lineIterable = DiffIterableUtil.create(fragments.map { Range(it.startLine1, it.endLine1, it.startLine2, it.endLine2) }, lineCount1, lineCount2) diff --git a/platform/diff-impl/tests/com/intellij/diff/util/DiffUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/util/DiffUtilTest.kt index 82732b3a6367..7f916e5e5d9e 100644 --- a/platform/diff-impl/tests/com/intellij/diff/util/DiffUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/util/DiffUtilTest.kt @@ -38,7 +38,6 @@ import com.intellij.openapi.diff.DiffBundle import com.intellij.openapi.editor.impl.DocumentImpl import com.intellij.util.containers.ContainerUtil import java.io.File -import java.util.* class DiffUtilTest : DiffTestCase() { fun `test getSortedIndexes`() { diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/NotRoamableUiSettings.kt b/platform/editor-ui-api/src/com/intellij/ide/ui/NotRoamableUiSettings.kt index 1850d4c7b4bb..b17b1dd0730d 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/NotRoamableUiSettings.kt +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/NotRoamableUiSettings.kt @@ -1,10 +1,7 @@ // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.ui -import com.intellij.openapi.components.BaseState -import com.intellij.openapi.components.PersistentStateComponent -import com.intellij.openapi.components.State -import com.intellij.openapi.components.Storage +import com.intellij.openapi.components.* import com.intellij.openapi.util.Pair import com.intellij.util.ui.UIUtil import com.intellij.util.xmlb.Accessor @@ -12,7 +9,7 @@ import com.intellij.util.xmlb.SerializationFilter import com.intellij.util.xmlb.annotations.Property import java.awt.Font -@State(name = "NotRoamableUiSettings", storages = [(Storage(Storage.NOT_ROAMABLE_FILE))], reportStatistic = true) +@State(name = "NotRoamableUiSettings", storages = [(Storage(StoragePathMacros.NOT_ROAMABLE_FILE))], reportStatistic = true) class NotRoamableUiSettings : PersistentStateComponent { private var state = NotRoamableUiOptions() diff --git a/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionPointImpl.java b/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionPointImpl.java index 1ad0c1f282f8..9693bab18773 100644 --- a/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionPointImpl.java +++ b/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionPointImpl.java @@ -41,12 +41,18 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { protected final ExtensionsAreaImpl myOwner; private final PluginDescriptor myDescriptor; - @NotNull protected Set myExtensionAdapters = Collections.emptySet(); // guarded by this + // guarded by this + @NotNull + protected Set myAdapters = Collections.emptySet(); + + @NotNull + // guarded by this + private List myLoadedAdapters = Collections.emptyList(); + @SuppressWarnings("unchecked") @NotNull - private ExtensionPointListener[] myEPListeners = ExtensionPointListener.EMPTY_ARRAY; // guarded by this - @NotNull - private List myLoadedAdapters = Collections.emptyList(); // guarded by this + // guarded by this + private ExtensionPointListener[] myListeners = ExtensionPointListener.EMPTY_ARRAY; @Nullable protected Class myExtensionClass; @@ -143,7 +149,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { } private void notifyListenersOnAdd(@NotNull T extension, @Nullable PluginDescriptor pluginDescriptor) { - for (ExtensionPointListener listener : myEPListeners) { + for (ExtensionPointListener listener : myListeners) { try { listener.extensionAdded(extension, pluginDescriptor); } @@ -200,7 +206,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { return !cache.isEmpty(); } synchronized (this) { - return myExtensionAdapters.size() + myLoadedAdapters.size() > 0; + return myAdapters.size() + myLoadedAdapters.size() > 0; } } @@ -210,7 +216,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { if (processingAdaptersNow) { throw new IllegalStateException("Recursive processAdapters() detected. You must have called 'getExtensions()' from within your extension constructor - don't. Either pass extension via constructor parameter or call getExtensions() later."); } - int totalSize = myExtensionAdapters.size() + myLoadedAdapters.size(); + int totalSize = myAdapters.size() + myLoadedAdapters.size(); Class extensionClass = getExtensionClass(); @SuppressWarnings("unchecked") T[] result = (T[])Array.newInstance(extensionClass, totalSize); @@ -221,11 +227,11 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { processingAdaptersNow = true; try { ExtensionComponentAdapter[] adapters = new ExtensionComponentAdapter[totalSize]; - myExtensionAdapters.toArray(adapters); - ArrayUtil.copy(myLoadedAdapters, adapters, myExtensionAdapters.size()); + myAdapters.toArray(adapters); + ArrayUtil.copy(myLoadedAdapters, adapters, myAdapters.size()); LoadingOrder.sort(adapters); - myExtensionAdapters = new LinkedHashSet<>(adapters.length); - ContainerUtil.addAll(myExtensionAdapters, adapters); + myAdapters = new LinkedHashSet<>(adapters.length); + ContainerUtil.addAll(myAdapters, adapters); Set loaded = ContainerUtil.newHashOrEmptySet(myLoadedAdapters); OpenTHashSet duplicates = new OpenTHashSet<>(adapters.length); @@ -263,9 +269,9 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { catch (Exception e) { LOG.error(e); } - myExtensionAdapters.remove(adapter); + myAdapters.remove(adapter); } - myExtensionAdapters = Collections.emptySet(); + myAdapters = Collections.emptySet(); if (extensionIndex != result.length) { result = Arrays.copyOf(result, extensionIndex); @@ -279,7 +285,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { // used in upsource public synchronized void removeUnloadableExtensions() { - ExtensionComponentAdapter[] adapters = myExtensionAdapters.toArray(ExtensionComponentAdapter.EMPTY_ARRAY); + ExtensionComponentAdapter[] adapters = myAdapters.toArray(ExtensionComponentAdapter.EMPTY_ARRAY); for (ExtensionComponentAdapter adapter : adapters) { try { adapter.getComponentImplementation(); @@ -322,7 +328,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { @Override public synchronized void unregisterExtension(@NotNull Class extensionClass) { - for (ExtensionComponentAdapter adapter : ContainerUtil.concat(myExtensionAdapters, myLoadedAdapters)) { + for (ExtensionComponentAdapter adapter : ContainerUtil.concat(myAdapters, myLoadedAdapters)) { if (adapter.getAssignableToClassName().equals(extensionClass.getCanonicalName())) { unregisterExtensionAdapter(adapter); return; @@ -352,7 +358,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { } private void notifyListenersOnRemove(@NotNull T extensionObject, PluginDescriptor pluginDescriptor) { - for (ExtensionPointListener listener : myEPListeners) { + for (ExtensionPointListener listener : myListeners) { try { listener.extensionRemoved(extensionObject, pluginDescriptor); } @@ -384,15 +390,15 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { // true if added private boolean addListener(@NotNull ExtensionPointListener listener) { - if (ArrayUtil.indexOf(myEPListeners, listener) != -1) return false; + if (ArrayUtil.indexOf(myListeners, listener) != -1) return false; //noinspection unchecked - myEPListeners = ArrayUtil.append(myEPListeners, listener, n->n==0?ExtensionPointListener.EMPTY_ARRAY:new ExtensionPointListener[n]); + myListeners = ArrayUtil.append(myListeners, listener, n-> n == 0 ? ExtensionPointListener.EMPTY_ARRAY : new ExtensionPointListener[n]); return true; } private boolean removeListener(@NotNull ExtensionPointListener listener) { - if (ArrayUtil.indexOf(myEPListeners, listener) == -1) return false; + if (ArrayUtil.indexOf(myListeners, listener) == -1) return false; //noinspection unchecked - myEPListeners = ArrayUtil.remove(myEPListeners, listener, n->n==0?ExtensionPointListener.EMPTY_ARRAY:new ExtensionPointListener[n]); + myListeners = ArrayUtil.remove(myListeners, listener, n-> n == 0 ? ExtensionPointListener.EMPTY_ARRAY : new ExtensionPointListener[n]); return true; } @@ -435,7 +441,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { @Override public synchronized void reset() { - myExtensionAdapters = Collections.emptySet(); + myAdapters = Collections.emptySet(); for (T extension : getExtensionList()) { unregisterExtension(extension); } @@ -468,10 +474,10 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { } synchronized void registerExtensionAdapter(@NotNull ExtensionComponentAdapter adapter) { - if (myExtensionAdapters == Collections.emptySet()) { - myExtensionAdapters = new LinkedHashSet<>(); + if (myAdapters == Collections.emptySet()) { + myAdapters = new LinkedHashSet<>(); } - myExtensionAdapters.add(adapter); + myAdapters.add(adapter); clearCache(); } @@ -482,7 +488,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { private void unregisterExtensionAdapter(@NotNull ExtensionComponentAdapter adapter) { try { - if (!myExtensionAdapters.isEmpty() && myExtensionAdapters.remove(adapter)) { + if (!myAdapters.isEmpty() && myAdapters.remove(adapter)) { return; } @@ -532,7 +538,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { @TestOnly final synchronized void notifyAreaReplaced(@NotNull ExtensionsArea oldArea) { - for (final ExtensionPointListener listener : myEPListeners) { + for (final ExtensionPointListener listener : myListeners) { if (listener instanceof ExtensionPointAndAreaListener) { ((ExtensionPointAndAreaListener)listener).areaReplaced(oldArea); } diff --git a/platform/extensions/src/com/intellij/openapi/extensions/impl/InterfaceExtensionPoint.java b/platform/extensions/src/com/intellij/openapi/extensions/impl/InterfaceExtensionPoint.java index 1113b3925358..c2bf41f3733f 100644 --- a/platform/extensions/src/com/intellij/openapi/extensions/impl/InterfaceExtensionPoint.java +++ b/platform/extensions/src/com/intellij/openapi/extensions/impl/InterfaceExtensionPoint.java @@ -32,7 +32,7 @@ public final class InterfaceExtensionPoint extends ExtensionPointImpl { @Override public synchronized void reset() { - for (Object extensionAdapter : myExtensionAdapters) { + for (Object extensionAdapter : myAdapters) { myOwner.getPicoContainer().unregisterComponent(((ComponentAdapter)extensionAdapter).getComponentKey()); } super.reset(); diff --git a/platform/icons/src/actions/stepOutCodeBlock.svg b/platform/icons/src/actions/stepOutCodeBlock.svg new file mode 100644 index 000000000000..a8ac444c7e68 --- /dev/null +++ b/platform/icons/src/actions/stepOutCodeBlock.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/platform/icons/src/actions/stepOutCodeBlock_dark.svg b/platform/icons/src/actions/stepOutCodeBlock_dark.svg new file mode 100644 index 000000000000..70fb551bba1e --- /dev/null +++ b/platform/icons/src/actions/stepOutCodeBlock_dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/platform/lang-api/src/com/intellij/ide/PsiActionSupportFactory.java b/platform/lang-api/src/com/intellij/ide/PsiActionSupportFactory.java index 65bb3b88b0ec..de8e3007f8ce 100644 --- a/platform/lang-api/src/com/intellij/ide/PsiActionSupportFactory.java +++ b/platform/lang-api/src/com/intellij/ide/PsiActionSupportFactory.java @@ -31,7 +31,7 @@ public abstract class PsiActionSupportFactory { return ServiceManager.getService(PsiActionSupportFactory.class); } - public static interface PsiElementSelector { + public interface PsiElementSelector { @NotNull PsiElement[] getSelectedElements(); } 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 2513341977fd..dc498134fe07 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 @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.application.options.colors; @@ -34,6 +34,7 @@ import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; import com.intellij.psi.search.scope.packageSet.PackageSet; import com.intellij.util.EventDispatcher; import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import gnu.trove.THashMap; import gnu.trove.THashSet; @@ -510,9 +511,13 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract initScheme(schemeDelegate); mySchemes.put(schemeDelegate.getName(), schemeDelegate); } - - mySelectedScheme = mySchemes.get(EditorColorsManager.getInstance().getGlobalScheme().getName()); - assert mySelectedScheme != null : EditorColorsManager.getInstance().getGlobalScheme().getName() + "; myschemes=" + mySchemes; + EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme(); + if (EditorColorsManagerImpl.isTempScheme(globalScheme)) { + mySelectedScheme = ContainerUtil.getFirstItem(mySchemes.values()); + } else { + mySelectedScheme = mySchemes.get(globalScheme.getName()); + } + assert mySelectedScheme != null : globalScheme.getName() + "; myschemes=" + mySchemes; } private static void initScheme(@NotNull MyColorScheme scheme) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/TargetElementUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/TargetElementUtil.java index fc7d1907bd46..754f825071ae 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/TargetElementUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/TargetElementUtil.java @@ -116,9 +116,13 @@ public class TargetElementUtil extends TargetElementUtilBase { PsiReference ref = file.findReferenceAt(adjustOffset(file, document, offset)); if (ref == null) return null; int elementOffset = ref.getElement().getTextRange().getStartOffset(); - if (ref.getRangeInElement().shiftRight(elementOffset).containsOffset(offset)) { - return ref; + + for (TextRange range : ReferenceRange.getRanges(ref)) { + if (range.shiftRight(elementOffset).containsOffset(offset)) { + return ref; + } } + return null; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/focusMode/FocusModePassFactory.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/focusMode/FocusModePassFactory.java index 626d8f9caf4d..5a024d7beb88 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/focusMode/FocusModePassFactory.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/focusMode/FocusModePassFactory.java @@ -6,6 +6,7 @@ import com.intellij.codeHighlighting.TextEditorHighlightingPass; import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory; import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar; import com.intellij.lang.LanguageExtension; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; @@ -13,10 +14,14 @@ import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.editor.impl.FocusModeModel; import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.Segment; import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiFile; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.util.TimeoutUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,6 +30,8 @@ import java.util.List; public class FocusModePassFactory implements TextEditorHighlightingPassFactory { private static final LanguageExtension EP_NAME = new LanguageExtension<>("com.intellij.focusModeProvider"); + private static final long MAX_ALLOWED_TIME = 100; + private static final Logger LOG = Logger.getInstance(FocusModePassFactory.class); public FocusModePassFactory(@NotNull TextEditorHighlightingPassRegistrar highlightingPassRegistrar) { highlightingPassRegistrar.registerTextEditorHighlightingPass(this, null, null, false, -1); @@ -45,12 +52,32 @@ public class FocusModePassFactory implements TextEditorHighlightingPassFactory { @Nullable public static List calcFocusZones(@Nullable PsiFile file) { if (file == null || !isEnabled()) return null; - FileViewProvider provider = file.getViewProvider(); + return CachedValuesManager.getCachedValue(file, () -> { + FileViewProvider provider = file.getViewProvider(); - return EP_NAME.allForLanguageOrAny(provider.getBaseLanguage()).stream() - .map(p -> p.calcFocusZones(file)) - .map(l -> ContainerUtil.append(l, file.getTextRange())) - .findFirst().orElse(null); + List segments = EP_NAME.allForLanguageOrAny(provider.getBaseLanguage()).stream() + .map(p -> calcFocusZones(p, file)) + .map(l -> ContainerUtil.append(l, file.getTextRange())) + .findFirst().orElse(null); + return CachedValueProvider.Result.create(segments, file); + }); + } + + /** + * Computes focus zones for the {@code psiFile} using {@code focusModeProvider}. Additionally warns, if zones building took too long + * (longer than {@link #MAX_ALLOWED_TIME} ms. + */ + @NotNull + private static List calcFocusZones(@NotNull FocusModeProvider focusModeProvider, @NotNull PsiFile psiFile) { + Ref> resultRef = Ref.create(); + long executionTime = TimeoutUtil.measureExecutionTime(() -> resultRef.set(focusModeProvider.calcFocusZones(psiFile))); + if (executionTime > MAX_ALLOWED_TIME) { + LOG.warn("Focus zones collecting took too long: " + executionTime + "ms; " + + "Provider: " + focusModeProvider.getClass().getSimpleName() + "; " + + "File size: " + psiFile.getTextLength() + "; " + + "Ranges collected: " + resultRef.get().size()); + } + return resultRef.get(); } public static void setToEditor(@NotNull List zones, Editor editor) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java index 0bffd17cb0d5..51bc59e370b5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java @@ -507,7 +507,7 @@ public class TypedHandler extends TypedActionHandlerBase { } } - if (isOpeningQuote(editor, quoteHandler, offset - 1) && hasNonClosedLiterals(editor, quoteHandler, offset - 1)) { + if (offset > 0 && isOpeningQuote(editor, quoteHandler, offset - 1) && hasNonClosedLiterals(editor, quoteHandler, offset - 1)) { if (offset == document.getTextLength() || !Character.isUnicodeIdentifierPart(document.getCharsSequence().charAt(offset))) { //any better heuristic or an API? document.insertString(offset, String.valueOf(quote)); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java index e34d7f847bc2..091afb99ecda 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java @@ -3,21 +3,18 @@ package com.intellij.codeInsight.navigation.actions; import com.google.common.annotations.VisibleForTesting; import com.intellij.codeInsight.CodeInsightActionHandler; -import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.TargetElementUtil; import com.intellij.codeInsight.actions.BaseCodeInsightAction; -import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.navigation.NavigationUtil; import com.intellij.diagnostic.PluginException; -import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.find.actions.ShowUsagesAction; import com.intellij.ide.util.DefaultPsiElementCellRenderer; import com.intellij.ide.util.EditSourceUtil; import com.intellij.injected.editor.EditorWindow; import com.intellij.lang.LanguageNamesValidation; import com.intellij.lang.refactoring.NamesValidator; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.actionSystem.ex.ActionUtil; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; @@ -30,9 +27,7 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbService; -import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.TextRange; import com.intellij.pom.Navigatable; @@ -56,13 +51,13 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -public class GotoDeclarationAction extends BaseCodeInsightAction implements CodeInsightActionHandler, DumbAware { +public class GotoDeclarationAction extends BaseCodeInsightAction implements DumbAware { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.navigation.actions.GotoDeclarationAction"); @NotNull @Override protected CodeInsightActionHandler getHandler() { - return this; + return GotoDeclarationActionHandler.INSTANCE; } @Override @@ -70,65 +65,6 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code return true; } - @Override - public void invoke(@NotNull final Project project, @NotNull Editor editor, @NotNull PsiFile file) { - - DumbService.getInstance(project).setAlternativeResolveEnabled(true); - try { - int offset = editor.getCaretModel().getOffset(); - PsiElement[] elements = underModalProgress(project, "Resolving Reference...", () -> findAllTargetElements(project, editor, offset)); - FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration"); - - if (elements.length != 1) { - if (elements.length == 0 && suggestCandidates(TargetElementUtil.findReference(editor, offset)).isEmpty()) { - PsiElement element = findElementToShowUsagesOf(editor, editor.getCaretModel().getOffset()); - if (startFindUsages(editor, project, element)) { - return; - } - - //disable 'no declaration found' notification for keywords - if (isKeywordUnderCaret(project, file, offset)) return; - } - chooseAmbiguousTarget(editor, offset, elements, file); - return; - } - - PsiElement element = elements[0]; - if (element == findElementToShowUsagesOf(editor, editor.getCaretModel().getOffset()) && - startFindUsages(editor, project, element)) { - return; - } - - PsiElement navElement = element.getNavigationElement(); - navElement = TargetElementUtil.getInstance().getGotoDeclarationTarget(element, navElement); - if (navElement != null) { - gotoTargetElement(navElement, editor, file); - } - } - catch (IndexNotReadyException e) { - DumbService.getInstance(project).showDumbModeNotification("Navigation is not available here during index update"); - } - finally { - DumbService.getInstance(project).setAlternativeResolveEnabled(false); - } - } - - private static boolean startFindUsages(@NotNull Editor editor, @NotNull Project project, PsiElement element) { - if (element == null) { - return false; - } - if (DumbService.getInstance(project).isDumb()) { - AnAction action = ActionManager.getInstance().getAction(ShowUsagesAction.ID); - String name = action.getTemplatePresentation().getText(); - DumbService.getInstance(project).showDumbModeNotification(ActionUtil.getUnavailableMessage(name, false)); - } - else { - RelativePoint popupPosition = JBPopupFactory.getInstance().guessBestPopupLocation(editor); - new ShowUsagesAction().startFindUsages(element, popupPosition, editor, ShowUsagesAction.getUsagesPageSize()); - } - return true; - } - static T underModalProgress(@NotNull Project project, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String progressTitle, @NotNull Computable computable) throws ProcessCanceledException { @@ -147,19 +83,6 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code return TargetElementUtil.getInstance().findTargetElement(editor, TargetElementUtil.ELEMENT_NAME_ACCEPTED, offset); } - private static void chooseAmbiguousTarget(final Editor editor, int offset, PsiElement[] elements, PsiFile currentFile) { - if (!editor.getComponent().isShowing()) return; - PsiElementProcessor navigateProcessor = element -> { - gotoTargetElement(element, editor, currentFile); - return true; - }; - boolean found = - chooseAmbiguousTarget(editor, offset, navigateProcessor, CodeInsightBundle.message("declaration.navigation.title"), elements); - if (!found) { - HintManager.getInstance().showErrorHint(editor, "Cannot find declaration to go to"); - } - } - private static boolean navigateInCurrentEditor(@NotNull PsiElement element, @NotNull PsiFile currentFile, @NotNull Editor currentEditor) { if (element.getContainingFile() == currentFile && !currentEditor.isDisposed()) { int offset = element.getTextOffset(); @@ -178,7 +101,7 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code return false; } - private static void gotoTargetElement(@NotNull PsiElement element, @NotNull Editor currentEditor, @NotNull PsiFile currentFile) { + static void gotoTargetElement(@NotNull PsiElement element, @NotNull Editor currentEditor, @NotNull PsiFile currentFile) { if (navigateInCurrentEditor(element, currentFile, currentEditor)) return; Navigatable navigatable = element instanceof Navigatable ? (Navigatable)element : EditSourceUtil.getDescriptor(element); @@ -240,11 +163,6 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code return TargetElementUtil.getInstance().getTargetCandidates(reference); } - @Override - public boolean startInWriteAction() { - return false; - } - @Nullable @TestOnly public static PsiElement findTargetElement(Project project, Editor editor, int offset) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationActionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationActionHandler.java new file mode 100644 index 000000000000..57110c01c929 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationActionHandler.java @@ -0,0 +1,68 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.codeInsight.navigation.actions; + +import com.intellij.codeInsight.CodeInsightActionHandler; +import com.intellij.find.actions.ShowUsagesAction; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.IndexNotReadyException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.ui.awt.RelativePoint; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import static com.intellij.codeInsight.navigation.actions.GotoDeclarationAction.findElementToShowUsagesOf; + +public final class GotoDeclarationActionHandler implements CodeInsightActionHandler { + + public static final GotoDeclarationActionHandler INSTANCE = new GotoDeclarationActionHandler(); + + @Override + public boolean startInWriteAction() { + return false; + } + + @Override + public void invoke(@NotNull final Project project, @NotNull Editor editor, @NotNull PsiFile file) { + final PsiElement declarationElement = findDeclarationElement(project, editor); + if (declarationElement == null) { + GotoDeclarationOnlyHandler.INSTANCE.invoke(project, editor, file); + } + else { + startFindUsages(editor, project, declarationElement); + } + } + + @Nullable + private static PsiElement findDeclarationElement(@NotNull Project project, @NotNull Editor editor) { + final DumbService dumbService = DumbService.getInstance(project); + try { + return dumbService.computeWithAlternativeResolveEnabled(() -> { + int offset = editor.getCaretModel().getOffset(); + return findElementToShowUsagesOf(editor, offset); + }); + } + catch (IndexNotReadyException e) { + dumbService.showDumbModeNotification("Navigation is not available here during index update"); + return null; + } + } + + private static void startFindUsages(@NotNull Editor editor, @NotNull Project project, @NotNull PsiElement element) { + if (DumbService.getInstance(project).isDumb()) { + AnAction action = ActionManager.getInstance().getAction(ShowUsagesAction.ID); + String name = action.getTemplatePresentation().getText(); + DumbService.getInstance(project).showDumbModeNotification(ActionUtil.getUnavailableMessage(name, false)); + } + else { + RelativePoint popupPosition = JBPopupFactory.getInstance().guessBestPopupLocation(editor); + new ShowUsagesAction().startFindUsages(element, popupPosition, editor, ShowUsagesAction.getUsagesPageSize()); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyAction.kt b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyAction.kt new file mode 100644 index 000000000000..393d3f64e82e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyAction.kt @@ -0,0 +1,12 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.codeInsight.navigation.actions + +import com.intellij.codeInsight.CodeInsightActionHandler + +/** + * Go To Declaration which doesn't invoke Show Usages if there are no declarations to go + */ +class GotoDeclarationOnlyAction : GotoDeclarationAction() { + + override fun getHandler(): CodeInsightActionHandler = GotoDeclarationOnlyHandler +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt new file mode 100644 index 000000000000..326d060aaa57 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt @@ -0,0 +1,93 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.codeInsight.navigation.actions + +import com.intellij.codeInsight.CodeInsightActionHandler +import com.intellij.codeInsight.CodeInsightBundle +import com.intellij.codeInsight.TargetElementUtil +import com.intellij.codeInsight.hint.HintManager +import com.intellij.codeInsight.navigation.NavigationUtil +import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction.* +import com.intellij.featureStatistics.FeatureUsageTracker +import com.intellij.ide.util.DefaultPsiElementCellRenderer +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.DumbService +import com.intellij.openapi.project.IndexNotReadyException +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.search.PsiElementProcessor +import com.intellij.util.toArray + +object GotoDeclarationOnlyHandler : CodeInsightActionHandler { + + override fun startInWriteAction(): Boolean = false + + override fun invoke(project: Project, editor: Editor, file: PsiFile) { + FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration") + + val dumbService = DumbService.getInstance(project) + try { + dumbService.isAlternativeResolveEnabled = true + val offset = editor.caretModel.offset + val elements = underModalProgress(project, "Resolving Reference...") { + findAllTargetElements(project, editor, offset) + } + + if (elements.size == 1) { + // simplest case + val element = elements[0] + val navElement = TargetElementUtil.getInstance().getGotoDeclarationTarget(element, element.navigationElement) + if (navElement != null) { + gotoTargetElement(navElement, editor, file) + } + } + else if (elements.isEmpty()) { + // this means either there is really nowhere to go or weird TargetElementUtil didn't return anything + val reference = TargetElementUtil.findReference(editor, offset) + if (reference != null) { + val targets = underModalProgress(project, "Resolving Reference...") { + TargetElementUtil.getInstance().getTargetCandidates(reference) + } + if (targets.isNotEmpty()) { + chooseAmbiguousTarget(editor, file, targets.toArray(PsiElement.EMPTY_ARRAY)) + return + } + } + //disable 'no declaration found' notification for keywords + if (!isKeywordUnderCaret(project, file, offset)) { + HintManager.getInstance().showErrorHint(editor, "Cannot find declaration to go to") + } + } + else { + chooseAmbiguousTarget(editor, file, elements) + } + } + catch (e: IndexNotReadyException) { + dumbService.showDumbModeNotification("Navigation is not available here during index update") + } + finally { + dumbService.isAlternativeResolveEnabled = false + } + } + + private fun chooseAmbiguousTarget(editor: Editor, file: PsiFile, elements: Array) { + if (!editor.component.isShowing) return + chooseAmbiguousTarget(editor, CodeInsightBundle.message("declaration.navigation.title"), elements) { element -> + gotoTargetElement(element, editor, file) + } + } + + private fun chooseAmbiguousTarget(editor: Editor, title: String, elements: Array, processor: (PsiElement) -> Unit) { + require(elements.isNotEmpty()) + if (elements.size == 1) { + val element = elements[0] + processor(element) + return + } + val psiElementProcessor = PsiElementProcessor { + processor(it) + true + } + NavigationUtil.getPsiElementPopup(elements, DefaultPsiElementCellRenderer(), title, psiElementProcessor).showInBestPositionFor(editor) + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardUsagesCollector.java b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardUsagesCollector.java index 60b42d22c242..ea756a58610c 100644 --- a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardUsagesCollector.java +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardUsagesCollector.java @@ -1,13 +1,17 @@ // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.execution.dashboard; +import com.intellij.execution.configurations.ConfigurationType; import com.intellij.internal.statistic.beans.UsageDescriptor; import com.intellij.internal.statistic.service.fus.collectors.ProjectUsagesCollector; +import com.intellij.internal.statistic.utils.PluginInfoDetectorKt; import com.intellij.internal.statistic.utils.StatisticsUtilKt; import com.intellij.openapi.project.Project; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.HashSet; +import java.util.List; import java.util.Set; /** @@ -24,9 +28,19 @@ public class RunDashboardUsagesCollector extends ProjectUsagesCollector { @Override public Set getUsages(@NotNull Project project) { final Set usages = new HashSet<>(); - final Set types = RunDashboardManager.getInstance(project).getTypes(); - usages.add(StatisticsUtilKt.getBooleanUsage("run.dashboard", !types.isEmpty())); - types.forEach(type -> usages.add(new UsageDescriptor(type))); + final Set dashboardTypes = RunDashboardManager.getInstance(project).getTypes(); + usages.add(StatisticsUtilKt.getBooleanUsage("run.dashboard", !dashboardTypes.isEmpty())); + if (!dashboardTypes.isEmpty()) { + List configurationTypes = ConfigurationType.CONFIGURATION_TYPE_EP.getExtensionList(); + for (String dashboardType : dashboardTypes) { + ConfigurationType configurationType = ContainerUtil.find(configurationTypes, type -> type.getId().equals(dashboardType)); + if (configurationType == null) continue; + + String key = PluginInfoDetectorKt.getPluginInfo(configurationType.getClass()).isDevelopedByJetBrains() ? + dashboardType : "third.party"; + usages.add(new UsageDescriptor(key)); + } + } return usages; } } diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java index 4b00b9fb1357..a2a165cbc58a 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java @@ -32,7 +32,7 @@ public class LivePreviewController implements LivePreview.Delegate, FindUtil.Rep private final Alarm myLivePreviewAlarm; protected SearchResults mySearchResults; private LivePreview myLivePreview; - private final boolean myReplaceDenied = false; + private static final boolean myReplaceDenied = false; private boolean mySuppressUpdate; private boolean myTrackingDocument; diff --git a/platform/lang-impl/src/com/intellij/ide/actions/CreateFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/CreateFileAction.java index b6faa4ff9d9a..3f8764809ea9 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/CreateFileAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/CreateFileAction.java @@ -21,6 +21,7 @@ import com.intellij.ide.IdeBundle; import com.intellij.idea.ActionsBundle; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.ex.FileTypeChooser; import com.intellij.openapi.project.DumbAware; @@ -231,10 +232,9 @@ public class CreateFileAction extends CreateElementActionBase implements DumbAwa final PsiDirectory psiDirectory = getDirectory(); final Project project = psiDirectory.getProject(); - final boolean[] result = {false}; - FileTypeChooser.getKnownFileTypeOrAssociate(psiDirectory.getVirtualFile(), getFileName(inputString), project); - result[0] = super.canClose(getFileName(inputString)); - return result[0]; + FileType fileType = FileTypeChooser.getKnownFileTypeOrAssociate(psiDirectory.getVirtualFile(), getFileName(inputString), project); + if (fileType == null) return false; + return super.canClose(getFileName(inputString)); } } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java index 90da9fd9a37a..3ed3f2a90235 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java @@ -55,7 +55,7 @@ public class GotoActionAction extends GotoActionBase implements DumbAware { @Override public void actionPerformed(@NotNull AnActionEvent e) { if (Registry.is("new.search.everywhere") && e.getProject() != null) { - showInSearchEverywherePopup(ActionSearchEverywhereContributor.class.getSimpleName(), e, false); + showInSearchEverywherePopup(ActionSearchEverywhereContributor.class.getSimpleName(), e, false, true); } else { super.actionPerformed(e); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java index 452cc3520593..9ed82f65806c 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java @@ -325,6 +325,10 @@ public abstract class GotoActionBase extends AnAction { } protected void showInSearchEverywherePopup(String searchProviderID, AnActionEvent evnt, boolean useEditorSelection) { + showInSearchEverywherePopup(searchProviderID, evnt, useEditorSelection, false); + } + + protected void showInSearchEverywherePopup(String searchProviderID, AnActionEvent evnt, boolean useEditorSelection, boolean sendStatistics) { SearchEverywhereManager seManager = SearchEverywhereManager.getInstance(evnt.getProject()); FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE + "." + searchProviderID); @@ -334,15 +338,19 @@ public abstract class GotoActionBase extends AnAction { } else { seManager.setShownContributor(searchProviderID); - String shortcut = KeymapUtil.getEventCallerKeystrokeText(evnt); - FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(searchProviderID, shortcut); - SearchEverywhereUsageTriggerCollector.trigger(evnt.getProject(), SearchEverywhereUsageTriggerCollector.TAB_SWITCHED, context); + if (sendStatistics) { + String shortcut = KeymapUtil.getEventCallerKeystrokeText(evnt); + FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(searchProviderID, shortcut); + SearchEverywhereUsageTriggerCollector.trigger(evnt.getProject(), SearchEverywhereUsageTriggerCollector.TAB_SWITCHED, context); + } } return; } - FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(searchProviderID, null); - SearchEverywhereUsageTriggerCollector.trigger(evnt.getProject(), SearchEverywhereUsageTriggerCollector.DIALOG_OPEN, context); + if (sendStatistics) { + FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(searchProviderID, null); + SearchEverywhereUsageTriggerCollector.trigger(evnt.getProject(), SearchEverywhereUsageTriggerCollector.DIALOG_OPEN, context); + } IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); String searchText = StringUtil.nullize(getInitialText(useEditorSelection, evnt).first); seManager.show(searchProviderID, searchText, evnt); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java index 5af1a1f98195..1dc87d6d6995 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java @@ -51,7 +51,7 @@ public class GotoClassAction extends GotoActionBase implements DumbAware { if (!DumbService.getInstance(project).isDumb()) { if (Registry.is("new.search.everywhere")) { - showInSearchEverywherePopup(ClassSearchEverywhereContributor.class.getSimpleName(), e, true); + showInSearchEverywherePopup(ClassSearchEverywhereContributor.class.getSimpleName(), e, true, true); } else { super.actionPerformed(e); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java index e2d72be2fdf5..d26cf90d7122 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java @@ -56,7 +56,7 @@ public class GotoFileAction extends GotoActionBase implements DumbAware { @Override public void actionPerformed(@NotNull AnActionEvent e) { if (Registry.is("new.search.everywhere")) { - showInSearchEverywherePopup(FileSearchEverywhereContributor.class.getSimpleName(), e, true); + showInSearchEverywherePopup(FileSearchEverywhereContributor.class.getSimpleName(), e, true, true); } else { super.actionPerformed(e); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java index cd73019b2da2..959df33ccab8 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java @@ -18,7 +18,7 @@ public class GotoSymbolAction extends GotoActionBase { @Override public void actionPerformed(@NotNull AnActionEvent e) { if (Registry.is("new.search.everywhere")) { - showInSearchEverywherePopup(SymbolSearchEverywhereContributor.class.getSimpleName(), e, true); + showInSearchEverywherePopup(SymbolSearchEverywhereContributor.class.getSimpleName(), e, true, true); } else { super.actionPerformed(e); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 38bcba0edb27..236b6a3e4251 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -584,7 +584,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA return; } - SearchEverywhereUsageTriggerCollector.trigger(e.getProject(), SearchEverywhereUsageTriggerCollector.DIALOG_OPEN, FUSUsageContext.create(searchProviderID)); + FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(searchProviderID, null); + SearchEverywhereUsageTriggerCollector.trigger(e.getProject(), SearchEverywhereUsageTriggerCollector.DIALOG_OPEN, context); IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); String text = GotoActionBase.getInitialTextForNavigation(e.getData(CommonDataKeys.EDITOR)); seManager.show(searchProviderID, text, e); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index 803d247b7161..ce81120898b8 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -445,7 +445,10 @@ public class SearchEverywhereUI extends BigPopupUI implements DataProvider, Quic @Override public void mousePressed(MouseEvent e) { switchToTab(SETab.this); - FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(getID(), "mouseClick"); + String reportableID = getContributor() + .map(SearchEverywhereUsageTriggerCollector::getReportableContributorID) + .orElse(SearchEverywhereManagerImpl.ALL_CONTRIBUTORS_GROUP_ID); + FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(reportableID, "mouseClick"); featureTriggered(SearchEverywhereUsageTriggerCollector.TAB_SWITCHED, context); } }); @@ -750,9 +753,12 @@ public class SearchEverywhereUI extends BigPopupUI implements DataProvider, Quic } private void triggerTabSwitched(AnActionEvent e) { - String selectedContributorID = getSelectedContributorID(); String shortcut = getEventShortcut(e).orElse(null); - FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(selectedContributorID, shortcut); + String id = mySelectedTab.getContributor() + .map(SearchEverywhereUsageTriggerCollector::getReportableContributorID) + .orElse(SearchEverywhereManagerImpl.ALL_CONTRIBUTORS_GROUP_ID); + + FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(id, shortcut); featureTriggered(SearchEverywhereUsageTriggerCollector.TAB_SWITCHED, context); } @@ -839,7 +845,8 @@ public class SearchEverywhereUI extends BigPopupUI implements DataProvider, Quic SearchEverywhereContributor contributor = myListModel.getContributorForIndex(i); Object value = myListModel.getElementAt(i); if (isAllTab) { - FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(contributor.getSearchProviderId(), null); + String reportableContributorID = SearchEverywhereUsageTriggerCollector.getReportableContributorID(contributor); + FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(reportableContributorID, null); featureTriggered(SearchEverywhereUsageTriggerCollector.CONTRIBUTOR_ITEM_SELECTED, context); } closePopup |= contributor.processSelectedItem(value, modifiers, searchText); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchEverywhereUsageTriggerCollector.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchEverywhereUsageTriggerCollector.java index 84600bbb090c..666c2307eb8f 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchEverywhereUsageTriggerCollector.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchEverywhereUsageTriggerCollector.java @@ -1,15 +1,23 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.actions.searcheverywhere.statistics; +import com.intellij.ide.actions.searcheverywhere.FileSearchEverywhereContributor; +import com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributor; import com.intellij.internal.statistic.eventLog.FeatureUsageData; import com.intellij.internal.statistic.service.fus.collectors.FUCounterUsageLogger; import com.intellij.internal.statistic.service.fus.collectors.FUSUsageContext; +import com.intellij.internal.statistic.utils.PluginInfo; +import com.intellij.internal.statistic.utils.PluginInfoDetectorKt; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class SearchEverywhereUsageTriggerCollector { + // this string will be used as ID for contributors from private + // plugins that mustn't be sent in statistics + private static final String NOT_REPORTABLE_CONTRIBUTOR_ID = "nonPublicContributor"; + public static final String DIALOG_OPEN = "dialogOpen"; public static final String TAB_SWITCHED = "tabSwitched"; public static final String GROUP_NAVIGATE = "navigateThroughGroups"; @@ -26,4 +34,11 @@ public class SearchEverywhereUsageTriggerCollector { public static FUSUsageContext createContext(@Nullable String contributorID, @Nullable String shortcut) { return FUSUsageContext.create(contributorID, shortcut); } + + @NotNull + public static String getReportableContributorID(@NotNull SearchEverywhereContributor contributor) { + Class clazz = contributor.getClass(); + PluginInfo pluginInfo = PluginInfoDetectorKt.getPluginInfo(clazz); + return pluginInfo.isSafeToReport() ? contributor.getSearchProviderId() : NOT_REPORTABLE_CONTRIBUTOR_ID; + } } diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesAutoscrollFromSourceHandler.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesAutoscrollFromSourceHandler.java index affef9d98712..298fd23928a7 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesAutoscrollFromSourceHandler.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesAutoscrollFromSourceHandler.java @@ -50,10 +50,6 @@ public class FavoritesAutoscrollFromSourceHandler extends AutoScrollFromSourceHa protected void selectElementFromEditor(@NotNull FileEditor editor) { VirtualFile file = FileEditorManagerEx.getInstanceEx(myProject).getFile(editor); PsiFile psiFile = file == null ? null : PsiManager.getInstance(myProject).findFile(file); - if (psiFile == null) return; - FileEditorSelectInContext context = new FileEditorSelectInContext(editor, psiFile); - if (mySelectInTarget.canSelect(context)) { - mySelectInTarget.selectIn(context, false); - } + if (psiFile != null) new FileEditorSelectInContext(editor, psiFile).selectIn(mySelectInTarget, false); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/ide/impl/ProjectViewSelectInGroupTarget.java b/platform/lang-impl/src/com/intellij/ide/impl/ProjectViewSelectInGroupTarget.java index 1c47070f8d2f..a3738e45dfac 100644 --- a/platform/lang-impl/src/com/intellij/ide/impl/ProjectViewSelectInGroupTarget.java +++ b/platform/lang-impl/src/com/intellij/ide/impl/ProjectViewSelectInGroupTarget.java @@ -48,7 +48,9 @@ public class ProjectViewSelectInGroupTarget implements CompositeSelectInTarget, } } targetsToCheck.addAll(targets); - targetsToCheck.stream().filter(t -> t.canSelect(context)).findFirst().ifPresent(target -> target.selectIn(context, requestFocus)); + for (SelectInTarget target : targetsToCheck) { + if (context.selectIn(target, requestFocus)) break; + } } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java b/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java index 9b93c4773560..ca1b2e67be4c 100644 --- a/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java @@ -124,9 +124,14 @@ public class StructureViewWrapperImpl implements StructureViewWrapper, Disposabl if (BitUtil.isSet(e.getChangeFlags(), HierarchyEvent.DISPLAYABILITY_CHANGED)) { boolean visible = myToolWindow.isVisible(); LOG.debug("displayability changed: " + visible); - if (!visible) return; // do nothing on hide - loggedRun("update file", StructureViewWrapperImpl.this::checkUpdate); - scheduleRebuild(); + if (visible) { + loggedRun("update file", StructureViewWrapperImpl.this::checkUpdate); + scheduleRebuild(); + } + else if (!myProject.isDisposed()) { + myFile = null; + loggedRun("clear a structure on hide", StructureViewWrapperImpl.this::rebuild); + } } } }); diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index 4130c79bb2bb..55122ccd7579 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -137,6 +137,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo private final AutoScrollToSourceHandler myAutoScrollToSourceHandler; private final MyAutoScrollFromSourceHandler myAutoScrollFromSourceHandler; + private volatile ThreeState myCurrentSelectionObsolete = ThreeState.NO; private final IdeView myIdeView = new IdeViewForProjectViewPane(this::getCurrentProjectViewPane); private final MyDeletePSIElementProvider myDeletePSIElementProvider = new MyDeletePSIElementProvider(); @@ -212,16 +213,15 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo @Override public void stateChanged() { ToolWindow window = toolWindowManager.getToolWindow(ToolWindowId.PROJECT_VIEW); - if (window == null) return; + if (window == null || toolWindowVisible == window.isVisible()) return; + myCurrentSelectionObsolete = ThreeState.NO; if (window.isVisible() && !toolWindowVisible) { - String id = getCurrentViewId(); AbstractProjectViewPane currentProjectViewPane = getCurrentProjectViewPane(); - if (currentProjectViewPane != null) { - if (isAutoscrollToSource(id)) { - myAutoScrollToSourceHandler.onMouseClicked(currentProjectViewPane.getTree()); - } - if (isAutoscrollFromSource(id)) { - myAutoScrollFromSourceHandler.setAutoScrollEnabled(true); + if (currentProjectViewPane != null && isAutoscrollFromSource(currentProjectViewPane.getId())) { + SimpleSelectInContext context = myAutoScrollFromSourceHandler.findSelectInContext(); + if (context != null) { + myCurrentSelectionObsolete = ThreeState.UNSURE; + context.selectInCurrentTarget(); } } } @@ -768,8 +768,20 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo } } + private boolean isCurrentSelectionObsolete(boolean requestFocus) { + if (myCurrentSelectionObsolete == ThreeState.YES) { + myCurrentSelectionObsolete = ThreeState.NO; + return true; + } + if (myCurrentSelectionObsolete == ThreeState.UNSURE) { + myCurrentSelectionObsolete = requestFocus ? ThreeState.YES : ThreeState.NO; + } + return false; + } + @Override public void select(final Object element, VirtualFile file, boolean requestFocus) { + if (isCurrentSelectionObsolete(requestFocus)) return; final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); if (viewPane != null) { viewPane.select(element, file, requestFocus); @@ -779,6 +791,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo @NotNull @Override public ActionCallback selectCB(Object element, VirtualFile file, boolean requestFocus) { + if (isCurrentSelectionObsolete(requestFocus)) return ActionCallback.REJECTED; final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); if (viewPane instanceof AbstractProjectViewPSIPane) { return ((AbstractProjectViewPSIPane)viewPane).selectCB(element, file, requestFocus); @@ -1317,7 +1330,6 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo @Override public void selectPsiElement(@NotNull PsiElement element, boolean requestFocus) { - if (element == null) return; VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element); select(element, virtualFile, requestFocus); } @@ -1871,38 +1883,37 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo @Override protected void selectElementFromEditor(@NotNull FileEditor fileEditor) { if (myProject.isDisposed() || !myViewContentPanel.isShowing()) return; - if (isAutoscrollFromSource(getCurrentViewId())) { - if (fileEditor instanceof TextEditor) { - TextEditor textEditor = (TextEditor)fileEditor; - selectElementAtCaretNotLosingFocus(textEditor.getEditor()); - } - else { - PsiFile psiFile = getPsiFile(getVirtualFile(fileEditor)); - if (psiFile != null) { - new MySelectInContext(psiFile, null).selectInCurrentTarget(); - } - } + if (isAutoscrollFromSource(getCurrentViewId()) && !isCurrentProjectViewPaneFocused()) { + SimpleSelectInContext context = getSelectInContext(fileEditor); + if (context != null) context.selectInCurrentTarget(); } } void scrollFromSource() { - FileEditorManager manager = FileEditorManager.getInstance(myProject); - if (scrollFromSource(manager.getSelectedEditor())) return; - for (FileEditor fileEditor : manager.getSelectedEditors()) { - if (scrollFromSource(fileEditor)) return; - } + SimpleSelectInContext context = findSelectInContext(); + if (context != null) context.selectInCurrentTarget(); } - private boolean scrollFromSource(FileEditor fileEditor) { + @Nullable + SimpleSelectInContext findSelectInContext() { + SimpleSelectInContext context = getSelectInContext(myFileEditorManager.getSelectedEditor()); + if (context != null) return context; + for (FileEditor fileEditor : myFileEditorManager.getSelectedEditors()) { + context = getSelectInContext(fileEditor); + if (context != null) return context; + } + return null; + } + + @Nullable + private SimpleSelectInContext getSelectInContext(@Nullable FileEditor fileEditor) { if (fileEditor instanceof TextEditor) { TextEditor textEditor = (TextEditor)fileEditor; - selectElementAtCaret(textEditor.getEditor()); - return true; + PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(textEditor.getEditor().getDocument()); + return psiFile == null ? null : new EditorSelectInContext(psiFile, textEditor.getEditor()); } PsiFile psiFile = getPsiFile(getVirtualFile(fileEditor)); - if (psiFile == null) return false; - scrollFromFile(psiFile, null); - return true; + return psiFile == null ? null : new SimpleSelectInContext(psiFile); } private PsiFile getPsiFile(VirtualFile file) { @@ -1913,23 +1924,9 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo return fileEditor == null ? null : FileEditorManagerEx.getInstanceEx(myProject).getFile(fileEditor); } - private void selectElementAtCaretNotLosingFocus(@NotNull Editor editor) { + private boolean isCurrentProjectViewPaneFocused() { AbstractProjectViewPane pane = getCurrentProjectViewPane(); - if (pane != null && !IJSwingUtilities.hasFocus(pane.getComponentToFocus())) { - selectElementAtCaret(editor); - } - } - - private void selectElementAtCaret(@NotNull Editor editor) { - final PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(editor.getDocument()); - if (file == null) return; - - scrollFromFile(file, editor); - } - - private void scrollFromFile(@NotNull PsiFile file, @Nullable Editor editor) { - MySelectInContext selectInContext = new MySelectInContext(file, editor); - PsiDocumentManager.getInstance(myProject).performLaterWhenAllCommitted(selectInContext::selectInCurrentTarget); + return pane != null && IJSwingUtilities.hasFocus(pane.getComponentToFocus()); } @Override @@ -1940,48 +1937,57 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo @Override protected void setAutoScrollEnabled(boolean state) { setAutoscrollFromSource(state, myCurrentViewId); - if (state) { - final Editor editor = myFileEditorManager.getSelectedTextEditor(); - if (editor != null) { - selectElementAtCaretNotLosingFocus(editor); - } + if (state && !isCurrentProjectViewPaneFocused()) { + scrollFromSource(); } createToolbarActions(); } + } - private class MySelectInContext extends SmartSelectInContext { - @Nullable private final Editor myEditor; + private class SimpleSelectInContext extends SmartSelectInContext { + SimpleSelectInContext(@NotNull PsiFile psiFile) { + super(psiFile, psiFile); + } - private MySelectInContext(@NotNull PsiFile psiFile, @Nullable Editor editor) { - super(psiFile, psiFile); - myEditor = editor; + void selectInCurrentTarget() { + SelectInTarget target = getCurrentSelectInTarget(); + if (target != null && getPsiFile() != null) { + selectIn(target, false); } + } - @Override - @NotNull - public FileEditorProvider getFileEditorProvider() { - return () -> ArrayUtil.getFirstElement(myFileEditorManager.openFile(getVirtualFile(), false)); - } + @Override + @NotNull + public FileEditorProvider getFileEditorProvider() { + return () -> ArrayUtil.getFirstElement(myFileEditorManager.openFile(getVirtualFile(), false)); + } + } - @Override - public Object getSelectorInFile() { - PsiFile file = getPsiFile(); - if (file != null && myEditor != null) { - final int offset = myEditor.getCaretModel().getOffset(); - PsiDocumentManager manager = PsiDocumentManager.getInstance(getProject()); - if (manager.hasUncommitedDocuments()) manager.commitAllDocuments(); - PsiElement element = file.findElementAt(offset); - if (element != null) return element; - } - return file; - } + private class EditorSelectInContext extends SimpleSelectInContext { + private final Editor editor; - void selectInCurrentTarget() { - SelectInTarget target = getCurrentSelectInTarget(); - if (target != null && getPsiFile() != null && target.canSelect(this)) { - target.selectIn(this, false); - } + EditorSelectInContext(@NotNull PsiFile psiFile, @NotNull Editor editor) { + super(psiFile); + this.editor = editor; + } + + @Override + void selectInCurrentTarget() { + PsiDocumentManager manager = PsiDocumentManager.getInstance(getProject()); + if (manager != null) manager.performLaterWhenAllCommitted(super::selectInCurrentTarget); + } + + @Override + public Object getSelectorInFile() { + PsiFile file = getPsiFile(); + if (file != null) { + int offset = editor.getCaretModel().getOffset(); + PsiDocumentManager manager = PsiDocumentManager.getInstance(getProject()); + if (manager.hasUncommitedDocuments()) manager.commitAllDocuments(); + PsiElement element = file.findElementAt(offset); + if (element != null) return element; } + return file; } } diff --git a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewTreeModel.java b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewTreeModel.java index ad1259fbe01f..3f92245e92e6 100644 --- a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewTreeModel.java +++ b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewTreeModel.java @@ -650,7 +650,9 @@ public final class ScopeViewTreeModel extends BaseTreeModel im attributes = SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES; } } - presentation.addText(title != null ? title : toString(), attributes); + String text = title != null ? title : toString(); + presentation.setPresentableText(text); + presentation.addText(text, attributes); Icon icon = getIcon(); if (icon == null && file.isValid()) { icon = file.isDirectory() @@ -1006,7 +1008,13 @@ public final class ScopeViewTreeModel extends BaseTreeModel im if (!groups.isEmpty() || roots.isEmpty()) return AllIcons.Nodes.ModuleGroup; Object id = roots.get(0).node.getRootID(); if (roots.stream().anyMatch(root -> !root.node.getRootID().equals(id))) return AllIcons.Nodes.ModuleGroup; - return id instanceof Module ? ModuleType.get((Module)id).getIcon() : AllIcons.Nodes.Module; + if (id instanceof Module) { + ModuleType type = ModuleType.get((Module)id); + Icon icon = type.getIcon(); + if (icon != null) return icon; + LOG.warn(type.getName() + " type have no icon for " + id); + } + return AllIcons.Nodes.Module; } @Nullable diff --git a/platform/lang-impl/src/com/intellij/ide/todo/FileTree.java b/platform/lang-impl/src/com/intellij/ide/todo/FileTree.java index 69c39b0f5b2e..a2e813614c68 100644 --- a/platform/lang-impl/src/com/intellij/ide/todo/FileTree.java +++ b/platform/lang-impl/src/com/intellij/ide/todo/FileTree.java @@ -16,6 +16,7 @@ package com.intellij.ide.todo; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; @@ -210,8 +211,11 @@ final class FileTree { List children = myDirectory2Children.get(dir); if (children != null) { for (VirtualFile child : children) { + ProgressManager.checkCanceled(); if (!child.isDirectory()) { - LOG.assertTrue(!filesList.contains(child)); + if (LOG.isDebugEnabled()) { + LOG.assertTrue(!filesList.contains(child)); + } filesList.add(child); } else { diff --git a/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java b/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java index eac9443d3c4d..f15718c99bb7 100644 --- a/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java +++ b/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java @@ -97,8 +97,14 @@ public class TraverseUIStarter extends ApplicationStarterEx { public static void startup(@NotNull final String outputPath, final boolean splitByResourcePath) throws IOException { Map> options = new LinkedHashMap<>(); try { + for (TraverseUIHelper extension : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension.beforeStart(); + SearchUtil.processProjectConfigurables(ProjectManager.getInstance().getDefaultProject(), options); + for (TraverseUIHelper extension1 : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension1.afterTraversal(options); + final Map roots = newHashMap(); for (SearchableConfigurable option : options.keySet()) { SearchableConfigurable configurable = option; @@ -149,6 +155,9 @@ public class TraverseUIStarter extends ApplicationStarterEx { JDOMUtil.writeDocument(new Document(entry.getValue()), output, "\n"); } + for (TraverseUIHelper extension : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension.afterResultsAreSaved(); + System.out.println("Searchable options index builder completed"); } finally { diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index f0ab0727fe8c..8087a745d8ab 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -134,7 +134,7 @@ public abstract class ChooseByNameBase implements ChooseByNameViewModel { private final int myRebuildDelay; private final Alarm myHideAlarm = new Alarm(); - private final boolean myShowListAfterCompletionKeyStroke = false; + private static final boolean myShowListAfterCompletionKeyStroke = false; protected JBPopup myTextPopup; protected JBPopup myDropdownPopup; diff --git a/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistAction.java b/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistAction.java new file mode 100644 index 000000000000..04cd1dc05285 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistAction.java @@ -0,0 +1,34 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.internal.statistic.actions; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.application.ex.ApplicationManagerEx; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class TestParseEventLogWhitelistAction extends DumbAwareAction { + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + final Project project = e.getProject(); + if (project != null) { + new TestParseEventLogWhitelistDialog(project, e.getData(CommonDataKeys.EDITOR)).show(); + } + } + + @Override + public void update(@NotNull AnActionEvent e) { + boolean enabled = isEnabled(e.getProject()); + e.getPresentation().setEnabledAndVisible(enabled); + if (enabled && e.getData(CommonDataKeys.EDITOR) == null) { + e.getPresentation().setEnabled(false); + } + } + + private static boolean isEnabled(@Nullable Project project) { + return project != null && ApplicationManagerEx.getApplicationEx().isInternal(); + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.form b/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.form new file mode 100644 index 000000000000..76fc305af526 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.form @@ -0,0 +1,83 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.java b/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.java new file mode 100644 index 000000000000..7503708172ea --- /dev/null +++ b/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.java @@ -0,0 +1,184 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.internal.statistic.actions; + +import com.intellij.internal.statistic.eventLog.*; +import com.intellij.internal.statistic.service.fus.FUStatisticsWhiteListGroupsService; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.highlighter.EditorHighlighter; +import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.BuildNumber; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.testFramework.LightVirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.util.Set; + +public class TestParseEventLogWhitelistDialog extends DialogWrapper { + private static final Logger LOG = Logger.getInstance(TestParseEventLogWhitelistDialog.class); + + private static final int IN_DIVIDER_LOCATION = 650; + private static final int IN_OUT_DIVIDER_LOCATION = 500; + private JPanel myMainPanel; + private JPanel myWhitelistPanel; + private JEditorPane myEventLogPanel; + private JSplitPane myInputDataSplitPane; + private JSplitPane myInputOutputSplitPane; + private JEditorPane myResultPane; + + private final Project myProject; + private final EditorEx myEditor; + + protected TestParseEventLogWhitelistDialog(@NotNull Project project, @Nullable Editor selectedEditor) { + super(project); + myProject = project; + setOKButtonText("&Filter Event Log"); + setCancelButtonText("&Close"); + Disposer.register(myProject, getDisposable()); + VirtualFile selectedFile = selectedEditor == null ? null : FileDocumentManager.getInstance().getFile(selectedEditor.getDocument()); + setTitle(selectedFile == null ? "Event Log Filter" : "Event Log Filter by: " + selectedFile.getName()); + myEditor = initEditor(selectedEditor); + myEditor.getSettings().setLineMarkerAreaShown(false); + + init(); + if (selectedEditor != null) { + doOKAction(); + + ApplicationManager.getApplication().invokeLater(() -> { + IdeFocusManager.getGlobalInstance() + .doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myEditor.getContentComponent(), true)); + myEditor.getCaretModel().moveToOffset(selectedEditor.getCaretModel().getOffset()); + myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + }, ModalityState.stateForComponent(myMainPanel)); + } + } + + @NotNull + private EditorEx initEditor(@Nullable Editor selectedEditor) { + if (selectedEditor != null) { + return (EditorEx)EditorFactory.getInstance().createEditor(selectedEditor.getDocument(), myProject); + } + else { + Document document = EditorFactory.getInstance().createDocument(StringUtil.notNullize("{}")); + EditorEx editor = (EditorEx)EditorFactory.getInstance().createEditor(document, myProject); + editor.getSelectionModel().setSelection(0, document.getTextLength()); + return editor; + } + } + + @Override + protected void init() { + configEditorPanel(myProject, myWhitelistPanel, myEditor); + + myInputDataSplitPane.setDividerLocation(IN_DIVIDER_LOCATION); + myInputOutputSplitPane.setDividerLocation(IN_OUT_DIVIDER_LOCATION); + super.init(); + } + + private static void configEditorPanel(@NotNull Project project, @NotNull JPanel panel, @NotNull EditorEx editor) { + panel.setLayout(new BorderLayout()); + panel.add(editor.getComponent(), BorderLayout.CENTER); + + editor.getSettings().setFoldingOutlineShown(false); + final FileType fileType = FileTypeManager.getInstance().findFileTypeByName("JSON"); + final LightVirtualFile lightFile = new LightVirtualFile("Dummy.json", fileType, ""); + + EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(project, lightFile); + try { + editor.setHighlighter(highlighter); + } + catch (Throwable e) { + LOG.warn(e); + } + } + + @Override + @NotNull + protected String getDimensionServiceKey() { + return TestParseEventLogWhitelistDialog.class.getCanonicalName(); + } + + @SuppressWarnings("TestOnlyProblems") + @Override + protected void doOKAction() { + myEditor.getSelectionModel().removeSelection(); + updateOutputText(""); + + final BuildNumber build = BuildNumber.fromString(EventLogConfiguration.INSTANCE.getBuild()); + final Set groups = FUStatisticsWhiteListGroupsService.parseApprovedGroups(myEditor.getDocument().getText(), build); + try { + final String parsed = parseLogAndFilter(new LogEventWhitelistFilter(groups), myEventLogPanel.getText()); + updateOutputText(parsed.trim()); + } + catch (IOException | ParseEventLogWhitelistException e) { + Messages.showErrorDialog(myProject, e.getMessage(), "Failed Applying Whitelist to Event Log"); + } + } + + private void updateOutputText(@NotNull String text) { + myResultPane.setText(text); + } + + @NotNull + private static String parseLogAndFilter(@NotNull LogEventFilter filter, @NotNull String text) + throws IOException, ParseEventLogWhitelistException { + final File log = FileUtil.createTempFile("feature-event-log", ".log"); + try { + FileUtil.writeToFile(log, text); + final LogEventRecordRequest request = LogEventRecordRequest.Companion.create(log, filter, true); + if (request == null) { + throw new ParseEventLogWhitelistException("Failed parsing event log"); + } + return LogEventSerializer.INSTANCE.toString(request); + } + finally { + FileUtil.delete(log); + } + } + + @Nullable + @Override + protected JComponent createCenterPanel() { + return myMainPanel; + } + + @Override + public JComponent getPreferredFocusedComponent() { + return myEventLogPanel; + } + + @Override + public void dispose() { + if (!myEditor.isDisposed()) { + EditorFactory.getInstance().releaseEditor(myEditor); + } + super.dispose(); + } + + public static class ParseEventLogWhitelistException extends Exception { + public ParseEventLogWhitelistException(String s) { + super(s); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorImpl.java b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorImpl.java index 361de262f16d..9bfe6b5ba376 100644 --- a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorImpl.java @@ -40,8 +40,8 @@ public class PsiAwareTextEditorImpl extends TextEditorImpl { @NotNull @Override - protected Runnable loadEditorInBackground() { - Runnable baseAction = super.loadEditorInBackground(); + protected AsyncEditorLoader.LoadEditorResult loadEditorInBackground() { + AsyncEditorLoader.LoadEditorResult baseResult = super.loadEditorInBackground(); PsiFile psiFile = PsiManager.getInstance(myProject).findFile(myFile); Document document = FileDocumentManager.getInstance().getDocument(myFile); boolean shouldBuildInitialFoldings = @@ -52,25 +52,26 @@ public class PsiAwareTextEditorImpl extends TextEditorImpl { List zones = FocusModePassFactory.calcFocusZones(psiFile); - return () -> { - baseAction.run(); - Editor editor = getEditor(); + return new AsyncEditorLoader.LoadEditorResult(baseResult.continuationValidator.and(d -> psiFile == null || psiFile.isValid()), + () -> { + baseResult.continuation.run(); + Editor editor = getEditor(); - if (foldingState != null) { - foldingState.setToEditor(editor); - } + if (foldingState != null) { + foldingState.setToEditor(editor); + } - if (zones != null) { - FocusModePassFactory.setToEditor(zones, editor); - if (editor instanceof EditorImpl) { - ((EditorImpl)editor).applyFocusMode(); - } - } + if (zones != null) { + FocusModePassFactory.setToEditor(zones, editor); + if (editor instanceof EditorImpl) { + ((EditorImpl)editor).applyFocusMode(); + } + } - if (psiFile != null && psiFile.isValid()) { - DaemonCodeAnalyzer.getInstance(myProject).restart(psiFile); - } - }; + if (psiFile != null && psiFile.isValid()) { + DaemonCodeAnalyzer.getInstance(myProject).restart(psiFile); + } + }); } @NotNull diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/components/ScrollablePanel.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/components/ScrollablePanel.java index a6a0bb429103..6bc08334b4e7 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/components/ScrollablePanel.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/components/ScrollablePanel.java @@ -21,7 +21,7 @@ import java.awt.*; public class ScrollablePanel extends JPanel implements Scrollable { private int myUnitHeight = -1; - private final int myUnitWidth = 10; + private static final int myUnitWidth = 10; public ScrollablePanel() { } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/layout/VerticalStackLayout.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/layout/VerticalStackLayout.java index 8bf1dabd917e..32eb20adc95c 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/layout/VerticalStackLayout.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/layout/VerticalStackLayout.java @@ -20,7 +20,7 @@ package com.intellij.openapi.roots.ui.componentsList.layout; import java.awt.*; public class VerticalStackLayout implements LayoutManager2 { - private final int myDefaultHeight = 200; + private static final int myDefaultHeight = 200; /** * Calculates the minimum size dimensions for the specified diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionToolWrapperWithHint.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionToolWrapperWithHint.java new file mode 100644 index 000000000000..781f98aaf97a --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionToolWrapperWithHint.java @@ -0,0 +1,9 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.profile.codeInspection.ui.inspectionsTree; + +public interface InspectionToolWrapperWithHint { + /** + * Hint will be displayed in gray after inspection name + */ + String getHint(); +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeRenderer.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeRenderer.java index 1266aa461505..28d886f50393 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeRenderer.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeRenderer.java @@ -61,6 +61,10 @@ public abstract class InspectionsConfigTreeRenderer extends DefaultTreeRenderer @Nullable private static String getHint(final Descriptor descriptor) { final InspectionToolWrapper toolWrapper = descriptor.getToolWrapper(); + + if (toolWrapper.getTool() instanceof InspectionToolWrapperWithHint) { + return ((InspectionToolWrapperWithHint)toolWrapper.getTool()).getHint(); + } if (toolWrapper instanceof LocalInspectionToolWrapper || toolWrapper instanceof GlobalInspectionToolWrapper && !((GlobalInspectionToolWrapper)toolWrapper).worksInBatchModeOnly()) { return null; diff --git a/platform/platform-api/src/com/intellij/ide/HelpTooltip.java b/platform/platform-api/src/com/intellij/ide/HelpTooltip.java index 464f88717b7f..af32d915cb50 100644 --- a/platform/platform-api/src/com/intellij/ide/HelpTooltip.java +++ b/platform/platform-api/src/com/intellij/ide/HelpTooltip.java @@ -68,7 +68,7 @@ import java.util.Map; * *

No HTML tagging is allowed in title or shortcut, they are supposed to be simple text strings.

*

Description is can be html formatted. You can use all possible html tagging in description just without enclosing - * <html> and </html> tags themselves. In description it's allowed to have <p/ or <p> tags between paragraphs. + * <html> and </html> tags themselves. In description it's allowed to have <p/> or <p> tags between paragraphs. * Paragraphs will be rendered with the standard (10px) offset from the title, from one another and from the link. * To force the line break in a paragraph use <br/>. Standard font coloring and styling is also available.

* diff --git a/platform/platform-api/src/com/intellij/ide/SelectInContext.java b/platform/platform-api/src/com/intellij/ide/SelectInContext.java index 0ed1282037f5..a57cc553454b 100644 --- a/platform/platform-api/src/com/intellij/ide/SelectInContext.java +++ b/platform/platform-api/src/com/intellij/ide/SelectInContext.java @@ -38,4 +38,15 @@ public interface SelectInContext { @Nullable FileEditorProvider getFileEditorProvider(); + + /** + * @param target an object that supports a context selection + * @param requestFocus specifies whether a focus request is needed or not + * @return {@code true} if a selection request is approved and executed by the given target + */ + default boolean selectIn(@NotNull SelectInTarget target, boolean requestFocus) { + if (!target.canSelect(this)) return false; + target.selectIn(this, requestFocus); + return true; + } } \ No newline at end of file diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java index ca6813684e47..cc1e39a70d68 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java @@ -40,10 +40,13 @@ public abstract class ActionPlaces { public static final String EDITOR_TOOLBAR = "EditorToolbar"; public static final String EDITOR_TAB_POPUP = "EditorTabPopup"; public static final String EDITOR_TAB = "EditorTab"; + public static final String EDITOR_GUTTER = "ICON_NAVIGATION"; + public static final String EDITOR_GUTTER_POPUP = "ICON_NAVIGATION_SECONDARY_BUTTON"; public static final String COMMANDER_POPUP = "CommanderPopup"; public static final String COMMANDER_TOOLBAR = "CommanderToolbar"; public static final String CONTEXT_TOOLBAR = "ContextToolbar"; public static final String TOOLWINDOW_TITLE = "ToolwindowTitle"; + public static final String TOOLWINDOW_CONTENT = "ToolwindowContent"; public static final String PROJECT_VIEW_POPUP = "ProjectViewPopup"; public static final String PROJECT_VIEW_TOOLBAR = "ProjectViewToolbar"; @@ -151,7 +154,7 @@ public abstract class ActionPlaces { FILEHISTORY_VIEW_TOOLBAR, RUN_CONFIGURATIONS_COMBOBOX, WELCOME_SCREEN, CHANGES_VIEW_TOOLBAR, DATABASE_VIEW_TOOLBAR, ACTION_PLACE_QUICK_LIST_POPUP_ACTION, PHING_EXPLORER_TOOLBAR, DOCK_MENU, PHING_MESSAGES_TOOLBAR, DIFF_TOOLBAR, ANALYZE_STACKTRACE_PANEL_TOOLBAR, TOUCHBAR_GENERAL, COMPOSER_EDITOR_NOTIFICATION_PANEL, COMPOSER_EDITOR_NOTIFICATION_PANEL_EXTRA, - COMPOSER_LOG_RERUN + COMPOSER_LOG_RERUN, EDITOR_GUTTER, TOOLWINDOW_CONTENT ); private static final Set ourPopupPlaces = ContainerUtil.newHashSet( @@ -163,7 +166,7 @@ public abstract class ActionPlaces { GUI_DESIGNER_PROPERTY_INSPECTOR_POPUP, CREATE_EJB_POPUP, CHANGES_VIEW_POPUP, DATABASE_VIEW_POPUP, REMOTE_HOST_VIEW_POPUP, REMOTE_HOST_DIALOG_POPUP, TFS_TREE_POPUP, ACTION_PLACE_VCS_QUICK_LIST_POPUP_ACTION, PHING_EXPLORER_POPUP, NAVIGATION_BAR_POPUP, JS_BUILD_TOOL_POPUP, - V8_CPU_PROFILING_POPUP, V8_HEAP_PROFILING_POPUP, V8_HEAP_PROFILING_POPUP, RUN_DASHBOARD_POPUP + V8_CPU_PROFILING_POPUP, V8_HEAP_PROFILING_POPUP, V8_HEAP_PROFILING_POPUP, RUN_DASHBOARD_POPUP, EDITOR_GUTTER_POPUP ); private static final String POPUP_PREFIX = "popup@"; diff --git a/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java b/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java index 5ccd0deec282..3ffc591d4d17 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java +++ b/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java @@ -167,10 +167,7 @@ public class OpenFileDescriptor implements Navigatable, Comparable%s", validationInfo.message)); - String text = v.getPreferredSpan(View.X_AXIS) > MAX_WIDTH.get() ? - String.format("
%s
", MAX_WIDTH.get(), validationInfo.message) : - String.format("
%s
", validationInfo.message); - - tipComponent.setContentType("text/html"); - tipComponent.setEditable(false); - tipComponent.addHyperlinkListener(hyperlinkListener); - tipComponent.setEditorKit(UIUtil.getHTMLEditorKit()); - - EditorKit kit = tipComponent.getEditorKit(); - if (kit instanceof HTMLEditorKit) { - StyleSheet css = ((HTMLEditorKit)kit).getStyleSheet(); - - css.addRule("a, a:link {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkColor()) + ";}"); - css.addRule("a:visited {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkVisitedColor()) + ";}"); - css.addRule("a:hover {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkHoverColor()) + ";}"); - css.addRule("a:active {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkPressedColor()) + ";}"); - css.addRule("body {background-color:#" + ColorUtil.toHex(validationInfo.warning ? warningBackgroundColor() : errorBackgroundColor()) + ";}"); - } - - if (tipComponent.getCaret() instanceof DefaultCaret) { - ((DefaultCaret)tipComponent.getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE); - } - - tipComponent.setCaretPosition(0); - tipComponent.setText(text); - - tipComponent.setBackground(validationInfo.warning ? warningBackgroundColor() : errorBackgroundColor()); - tipComponent.setOpaque(true); - tipComponent.setBorder(getBorder()); - tipComponent.addMouseListener(new TipComponentMouseListener()); - - popupSize = tipComponent.getPreferredSize(); - - popupBuilder = JBPopupFactory.getInstance().createComponentPopupBuilder(tipComponent, null). - setBorderColor(validationInfo.warning ? warningBorderColor() : errorBorderColor()). - setCancelOnClickOutside(false). - setCancelOnMouseOutCallback(e -> e.getID() == MouseEvent.MOUSE_PRESSED && !withinComponent(e)). - setShowShadow(false); + popupBuilder = createPopupBuilder(validationInfo, tipComponent -> { + tipComponent.addHyperlinkListener(hyperlinkListener); + tipComponent.addMouseListener(new TipComponentMouseListener()); + popupSize = tipComponent.getPreferredSize(); + }); getFocusable(validationInfo.component).ifPresent(fc -> { if (fc.hasFocus()) { @@ -253,9 +232,54 @@ public class ComponentValidator { } } - private boolean withinComponent(@NotNull MouseEvent e) { - if (validationInfo != null && validationInfo.component != null && validationInfo.component.isShowing()) { - Rectangle screenBounds = new Rectangle(validationInfo.component.getLocationOnScreen(), validationInfo.component.getSize()); + @NotNull + public static ComponentPopupBuilder createPopupBuilder(@NotNull ValidationInfo info, @Nullable Consumer configurator) { + JEditorPane tipComponent = new JEditorPane(); + View v = BasicHTML.createHTMLView(tipComponent, String.format("%s", info.message)); + String text = v.getPreferredSpan(View.X_AXIS) > MAX_WIDTH.get() ? + String.format("
%s
", MAX_WIDTH.get(), info.message) : + String.format("
%s
", info.message); + + tipComponent.setContentType("text/html"); + tipComponent.setEditable(false); + tipComponent.setEditorKit(UIUtil.getHTMLEditorKit()); + + EditorKit kit = tipComponent.getEditorKit(); + if (kit instanceof HTMLEditorKit) { + StyleSheet css = ((HTMLEditorKit)kit).getStyleSheet(); + + css.addRule("a, a:link {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkColor()) + ";}"); + css.addRule("a:visited {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkVisitedColor()) + ";}"); + css.addRule("a:hover {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkHoverColor()) + ";}"); + css.addRule("a:active {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkPressedColor()) + ";}"); + css.addRule("body {background-color:#" + ColorUtil.toHex(info.warning ? warningBackgroundColor() : errorBackgroundColor()) + ";}"); + } + + if (tipComponent.getCaret() instanceof DefaultCaret) { + ((DefaultCaret)tipComponent.getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE); + } + + tipComponent.setCaretPosition(0); + tipComponent.setText(text); + + tipComponent.setBackground(info.warning ? warningBackgroundColor() : errorBackgroundColor()); + tipComponent.setOpaque(true); + tipComponent.setBorder(getBorder()); + + if (configurator != null) { + configurator.accept(tipComponent); + } + + return JBPopupFactory.getInstance().createComponentPopupBuilder(tipComponent, null). + setBorderColor(info.warning ? warningBorderColor() : errorBorderColor()). + setCancelOnClickOutside(false). + setShowShadow(false). + setCancelOnMouseOutCallback(e -> e.getID() == MouseEvent.MOUSE_PRESSED && !withinComponent(info, e)); + } + + private static boolean withinComponent(@NotNull ValidationInfo info, @NotNull MouseEvent e) { + if (info.component != null && info.component.isShowing()) { + Rectangle screenBounds = new Rectangle(info.component.getLocationOnScreen(), info.component.getSize()); return screenBounds.contains(e.getLocationOnScreen()); } else { @@ -279,15 +303,18 @@ public class ComponentValidator { } } - private void hidePopup() { + private void hidePopup(boolean now) { if (popup != null && popup.isVisible()) { - popupAlarm.cancelAllRequests(); - popupAlarm.addRequest(() -> { - if (popup != null && (!isOverPopup || hyperlinkListener == null)) { - popup.cancel(); - popup = null; - } - }, Registry.intValue("ide.tooltip.initialDelay.highlighter")); + if (now || hyperlinkListener == null) { + popup.cancel(); + popup = null; + } else { + popupAlarm.addRequest(() -> { + if (!isOverPopup || hyperlinkListener == null) { + hidePopup(true); + } + }, Registry.intValue("ide.tooltip.initialDelay.highlighter")); + } } } @@ -310,7 +337,7 @@ public class ComponentValidator { @Override public void focusLost(FocusEvent e) { - hidePopup(); + hidePopup(false); ValidationInfo info = null; if (focusValidator != null) { @@ -337,7 +364,7 @@ public class ComponentValidator { if (validationInfo != null) { getFocusable(validationInfo.component).ifPresent(fc -> { if (!fc.hasFocus()) { - hidePopup(); + hidePopup(false); } }); } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java index f615532188b6..7dfe59565f24 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java @@ -1784,27 +1784,30 @@ public abstract class DialogWrapper { } private void logCloseDialogEvent(int exitCode) { - final String dialogId = getLoggedDialogId(); - if (StringUtil.isNotEmpty(dialogId)) { - FeatureUsageUiEventsKt.getUiEventLogger().logCloseDialog(dialogId, exitCode, getClass()); + final boolean canRecord = canRecordDialogId(); + if (canRecord) { + final String dialogId = getClass().getName(); + if (StringUtil.isNotEmpty(dialogId)) { + FeatureUsageUiEventsKt.getUiEventLogger().logCloseDialog(dialogId, exitCode, getClass()); + } } } private void logShowDialogEvent() { - final String dialogId = getLoggedDialogId(); - if (StringUtil.isNotEmpty(dialogId)) { - FeatureUsageUiEventsKt.getUiEventLogger().logShowDialog(dialogId, getClass()); + final boolean canRecord = canRecordDialogId(); + if (canRecord) { + final String dialogId = getClass().getName(); + if (StringUtil.isNotEmpty(dialogId)) { + FeatureUsageUiEventsKt.getUiEventLogger().logShowDialog(dialogId, getClass()); + } } } /** - * The ID will be recorded in user event log, it can be used to understand how often this dialog is used. - * - * @return null if we shouldn't record the dialog. + * If dialog open/close events should be recorded in user event log, it can be used to understand how often this dialog is used. */ - @Nullable - protected String getLoggedDialogId() { - return getClass().getName(); + protected boolean canRecordDialogId() { + return true; } /** @@ -2050,8 +2053,8 @@ public abstract class DialogWrapper { } new Thread("DialogWrapper resizer") { - final int time = 200; - final int steps = 7; + static final int time = 200; + static final int steps = 7; @Override public void run() { diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java index 130ce71d20a4..c43ef5bd384a 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java @@ -815,8 +815,9 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom @NotNull public String getDisplayName() { final NamedConfigurable configurable = (NamedConfigurable)getUserObject(); - LOG.assertTrue(configurable != null, "Tree was already disposed"); - return configurable.getDisplayName(); + if (configurable != null) return configurable.getDisplayName(); + LOG.debug("Tree was already disposed"); // workaround for IDEA-206547 + return "DISPOSED"; } public NamedConfigurable getConfigurable() { diff --git a/platform/platform-api/src/com/intellij/openapi/ui/ValidationInfo.java b/platform/platform-api/src/com/intellij/openapi/ui/ValidationInfo.java index 5a2fe565cd22..912823ddb56a 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/ValidationInfo.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/ValidationInfo.java @@ -68,6 +68,11 @@ public final class ValidationInfo { return this; } + public ValidationInfo forComponent(@Nullable JComponent component) { + ValidationInfo result = new ValidationInfo(message, component); + return warning ? result.asWarning() : result; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java new file mode 100644 index 000000000000..84f20e2a411e --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java @@ -0,0 +1,67 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.ui.cellvalidators; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.table.TableCellRenderer; +import java.awt.*; +import java.awt.event.MouseEvent; + +@ApiStatus.Experimental +public abstract class CellComponentProvider { + @NotNull protected final C owner; + + public CellComponentProvider(@NotNull C owner) { + this.owner = owner; + } + + @NotNull + public final C getOwner() { + return owner; + } + + @Nullable + abstract public JComponent getCellRendererComponent(@NotNull Point p); + + @NotNull + abstract public Rectangle getCellRect(@NotNull MouseEvent e); + + public static CellComponentProvider forTable(JTable table) { + return new TableProvider(table); + } + + /** + * Convenient classes with standard implementations. Don't use the class directly. + * It can either be created with {@link CellComponentProvider#forTable(JTable)} method or + * be extended. + */ + public static class TableProvider extends CellComponentProvider { + protected TableProvider(@NotNull JTable owner) { + super(owner); + } + + @Nullable + @Override + public JComponent getCellRendererComponent(@NotNull Point p) { + int column = owner.columnAtPoint(p); + int row = owner.rowAtPoint(p); + + if ((column != -1) && (row != -1)) { + TableCellRenderer renderer = owner.getCellRenderer(row, column); + return (JComponent)owner.prepareRenderer(renderer, row, column); + } else { + return null; + } + } + + @NotNull + @Override + public Rectangle getCellRect(@NotNull MouseEvent e) { + Point p = e.getPoint(); + return owner.getCellRect(owner.rowAtPoint(p), owner.columnAtPoint(p), true); + } + } +} \ No newline at end of file diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java new file mode 100644 index 000000000000..6434a5a7e922 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java @@ -0,0 +1,187 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.ui.cellvalidators; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.ui.ComponentValidator; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.ui.popup.ComponentPopupBuilder; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.Alarm; +import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.HyperlinkListener; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.regex.Pattern; + +public final class CellTooltipManager { + private static final Pattern HTML_A_TAG_PATTERN = Pattern.compile("(?i)]+)>(.+?)"); + + private final Disposable parentDisposable; + + private CellComponentProvider cellComponentProvider; + private HyperlinkListener hyperlinkListener; + + private final Alarm popupAlarm = new Alarm(); + + private ValidationInfo validationInfo; + private boolean closeWithDelay; + + private ComponentPopupBuilder popupBuilder; + private JBPopup cellPopup; + private Point cellLocation; + private Dimension popupSize; + private boolean isOverPopup; + private boolean isClosing; + + @ApiStatus.Experimental + public CellTooltipManager(@NotNull Disposable parentDisposable) { + this.parentDisposable = parentDisposable; + } + + @ApiStatus.Experimental + public CellTooltipManager withCellComponentProvider(@NotNull CellComponentProvider cellComponentProvider) { + this.cellComponentProvider = cellComponentProvider; + return this; + } + + @ApiStatus.Experimental + public CellTooltipManager withHyperlinkListener(@NotNull HyperlinkListener hyperlinkListener) { + this.hyperlinkListener = hyperlinkListener; + return this; + } + + @ApiStatus.Experimental + public void installOn(@NotNull JComponent component) { + MouseAdapter mouseListener = new ValidationMouseListener(); + + component.addMouseListener(mouseListener); + component.addMouseMotionListener(mouseListener); + + Disposer.register(parentDisposable, () -> { + hidePopup(true, null); + + component.removeMouseListener(mouseListener); + component.removeMouseMotionListener(mouseListener); + + cellComponentProvider = null; + validationInfo = null; + popupBuilder = null; + }); + } + + private void handleMouseEvent(MouseEvent e) { + if (cellComponentProvider != null) { + JComponent cellRenderer = cellComponentProvider.getCellRendererComponent(e.getPoint()); + ValidationInfo info = cellRenderer != null ? (ValidationInfo)cellRenderer.getClientProperty(ValidatingTableCellRendererWrapper.CELL_VALIDATION_PROPERTY) : null; + + if (info != null) { + if (!info.equals(validationInfo)) { + validationInfo = info; + closeWithDelay = hasATag(validationInfo.message); + + popupBuilder = ComponentValidator.createPopupBuilder(validationInfo, tipComponent -> { + if (closeWithDelay) { + tipComponent.addHyperlinkListener(hyperlinkListener); + tipComponent.addMouseListener(new TipComponentMouseListener()); + } + popupSize = tipComponent.getPreferredSize(); + }); + + hidePopup(false, () -> showPopup(e)); + } + else if (!isShowing()) { + showPopup(e); + } + else if (!isClosing) { // Move popup to new location + Point location = cellComponentProvider.getCellRect(e).getLocation(); + if (!location.equals(cellLocation)) { + cellLocation = location; + Point point = new Point(cellLocation.x + JBUI.scale(40), cellLocation.y - JBUI.scale(6) - popupSize.height); + SwingUtilities.convertPointToScreen(point, cellComponentProvider.getOwner()); + cellPopup.setLocation(point); + } + } + } else { + validationInfo = null; + hidePopup(false, null); + } + } + } + + private static boolean hasATag(@NotNull String string) { + return HTML_A_TAG_PATTERN.matcher(string).find(); + } + + private void showPopup(MouseEvent e) { + cellPopup = popupBuilder.createPopup(); + cellLocation = cellComponentProvider.getCellRect(e).getLocation(); + Point point = new Point(cellLocation.x + JBUI.scale(40), cellLocation.y - JBUI.scale(6) - popupSize.height); + cellPopup.show(new RelativePoint(cellComponentProvider.getOwner(), point)); + } + + private void hidePopup(boolean now, @Nullable Runnable onHidden) { + if (isShowing()) { + if (now || hyperlinkListener == null || !closeWithDelay) { + cellPopup.cancel(); + cellPopup = null; + + if (onHidden != null) { + onHidden.run(); + } + } else if (!isClosing) { + isClosing = true; + popupAlarm.addRequest(() -> { + isClosing = false; + if (!isOverPopup) { + hidePopup(true, onHidden); + } + }, Registry.intValue("ide.tooltip.initialDelay.highlighter")); + } + } else if (onHidden != null) { + onHidden.run(); + } + } + + private boolean isShowing() { + return cellPopup != null && cellPopup.isVisible(); + } + + private class ValidationMouseListener extends MouseAdapter { + @Override + public void mouseEntered(MouseEvent e) { + handleMouseEvent(e); + } + + @Override + public void mouseExited(MouseEvent e) { + hidePopup(false, null); + } + + @Override + public void mouseMoved(MouseEvent e) { + handleMouseEvent(e); + } + } + + private class TipComponentMouseListener extends MouseAdapter { + @Override + public void mouseEntered(MouseEvent e) { + isOverPopup = true; + } + + @Override + public void mouseExited(MouseEvent e) { + isOverPopup = false; + hidePopup(true, null); + } + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/StatefulValidatingCellEditor.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/StatefulValidatingCellEditor.java new file mode 100644 index 000000000000..b1d9743bfba0 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/StatefulValidatingCellEditor.java @@ -0,0 +1,94 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.ui.cellvalidators; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.ui.ComponentValidator; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.util.Disposer; +import com.intellij.ui.DocumentAdapter; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.ItemListener; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import static com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper.CELL_VALIDATION_PROPERTY; + +public class StatefulValidatingCellEditor extends DefaultCellEditor implements Supplier { + private Consumer stateUpdater = (vi) -> {}; + + public StatefulValidatingCellEditor(JTextField textField, Disposable disposable) { + super(textField); + editorComponent.putClientProperty("JComponent.compactHeight", Boolean.TRUE); + new ComponentValidator(disposable).withValidator(this).installOn(editorComponent); + + DocumentListener dl = new DocumentAdapter() { + @Override + protected void textChanged(@NotNull DocumentEvent e) { + editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); + ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); + } + }; + + textField.getDocument().addDocumentListener(dl); + Disposer.register(disposable, () -> textField.getDocument().removeDocumentListener(dl)); + } + + public StatefulValidatingCellEditor(JComboBox comboBox, Disposable disposable) { + super(comboBox); + editorComponent.putClientProperty("JComponent.compactHeight", Boolean.TRUE); + new ComponentValidator(disposable).withValidator(this).installOn(editorComponent); + + ItemListener il = e -> { + editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); + ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); + }; + + comboBox.addItemListener(il); + Disposer.register(disposable, () -> comboBox.removeItemListener(il)); + } + + @ApiStatus.Experimental + public StatefulValidatingCellEditor withStateUpdater(@NotNull Consumer stateUpdater) { + this.stateUpdater = stateUpdater; + return this; + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + JComponent editor = (JComponent)super.getTableCellEditorComponent(table, value, isSelected, row, column); + JComponent renderer = (JComponent)table.getCellRenderer(row, column).getTableCellRendererComponent(table, value, isSelected, true, row, column); + ValidationInfo cellInfo = renderer != null ? (ValidationInfo)renderer.getClientProperty(CELL_VALIDATION_PROPERTY) : null; + if (cellInfo != null) { + editor.putClientProperty(CELL_VALIDATION_PROPERTY, cellInfo.forComponent(editor)); + ComponentValidator.getInstance(editor).ifPresent(ComponentValidator::revalidate); + } + return editor; + } + + @Override + public boolean stopCellEditing() { + editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); + ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); + return super.stopCellEditing(); + } + + @Override + public void cancelCellEditing() { + editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); + ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); + super.cancelCellEditing(); + } + + @Override + public ValidationInfo get() { + ValidationInfo info = (ValidationInfo)editorComponent.getClientProperty(CELL_VALIDATION_PROPERTY); + stateUpdater.accept(info); + return info; + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/TableCellValidator.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/TableCellValidator.java new file mode 100644 index 000000000000..0fbb42759f27 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/TableCellValidator.java @@ -0,0 +1,10 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.ui.cellvalidators; + +import com.intellij.openapi.ui.ValidationInfo; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Experimental +public interface TableCellValidator { + ValidationInfo validate(Object value, int row, int column); +} diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java new file mode 100644 index 000000000000..3cf1e24afd91 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java @@ -0,0 +1,84 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.ui.cellvalidators; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.ui.CellRendererPanel; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.table.TableCellRenderer; +import java.awt.*; +import java.util.function.Supplier; + +public class ValidatingTableCellRendererWrapper extends CellRendererPanel implements TableCellRenderer { + public static final String CELL_VALIDATION_PROPERTY = "CellRenderer.validationInfo"; + + private final TableCellRenderer delegate; + private final JLabel iconLabel = new JLabel(); + + private Supplier editorSizeSupplier = () -> JBUI.emptySize(); + private TableCellValidator cellValidator; + + @ApiStatus.Experimental + public ValidatingTableCellRendererWrapper(TableCellRenderer delegate) { + this.delegate = delegate; + setLayout(new BorderLayout(0, 0)); + add(iconLabel, BorderLayout.EAST); + + iconLabel.setOpaque(false); + setName("Table.cellRenderer"); + } + + @ApiStatus.Experimental + public ValidatingTableCellRendererWrapper bindToEditorSize(@NotNull Supplier editorSizeSupplier) { + this.editorSizeSupplier = editorSizeSupplier; + return this; + } + + @ApiStatus.Experimental + public ValidatingTableCellRendererWrapper withCellValidator(@NotNull TableCellValidator cellValidator) { + this.cellValidator = cellValidator; + return this; + } + + @Override + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + size.height = Math.max(size.height, editorSizeSupplier.get().height); + return size; + } + + @Override + public final Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JComponent delegateRenderer = (JComponent)delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + if (cellValidator != null) { + ValidationInfo result = cellValidator.validate(value, row, column); + iconLabel.setIcon(result == null ? null : result.warning ? AllIcons.General.BalloonWarning : AllIcons.General.BalloonError); + iconLabel.setBorder(result == null ? null: iconBorder()); + putClientProperty(CELL_VALIDATION_PROPERTY, result); + } + + add(delegateRenderer, BorderLayout.CENTER); + setBorder(delegateRenderer.getBorder()); + delegateRenderer.setBorder(null); + + setBackground(delegateRenderer.getBackground()); + return this; + } + + private static Border iconBorder() { + return JBUI.Borders.emptyRight(UIUtil.isUnderWin10LookAndFeel() ? 4 : 3); + } + + @Override + protected void paintComponent(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0, 0, getWidth(), getHeight()); + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidationUtils.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidationUtils.java new file mode 100644 index 000000000000..a987340697ca --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidationUtils.java @@ -0,0 +1,37 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.ui.cellvalidators; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.ui.components.fields.ExtendableTextComponent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public final class ValidationUtils { + private ValidationUtils() {} + + public final static ExtendableTextComponent.Extension ERROR_EXTENSION = + ExtendableTextComponent.Extension.create(AllIcons.General.BalloonError, null, null); + + public final static ExtendableTextComponent.Extension WARNING_EXTENSION = + ExtendableTextComponent.Extension.create(AllIcons.General.BalloonWarning, null, null); + + public static void setExtension(@NotNull ExtendableTextComponent editor, @NotNull ExtendableTextComponent.Extension extension, boolean set) { + if (set) { + editor.addExtension(extension); + } else { + editor.removeExtension(extension); + } + } + + public static void setExtension(@NotNull ExtendableTextComponent editor, @Nullable ValidationInfo vi) { + if (vi == null) { + editor.removeExtension(ERROR_EXTENSION); + editor.removeExtension(WARNING_EXTENSION); + } else if (vi.warning) { + editor.addExtension(WARNING_EXTENSION); + } else { + editor.addExtension(ERROR_EXTENSION); + } + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/wm/AppIconScheme.java b/platform/platform-api/src/com/intellij/openapi/wm/AppIconScheme.java index 2ee5e36fa467..52345dc1df53 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/AppIconScheme.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/AppIconScheme.java @@ -26,7 +26,7 @@ public class AppIconScheme { public interface Progress { - static final Progress TESTS = new Progress() { + Progress TESTS = new Progress() { @Override public Color getOkColor() { return TESTS_OK_COLOR; @@ -38,7 +38,7 @@ public class AppIconScheme { } }; - static final Progress BUILD = new Progress() { + Progress BUILD = new Progress() { @Override public Color getOkColor() { return BUILD_OK_COLOR; @@ -50,7 +50,7 @@ public class AppIconScheme { } }; - static final Progress INDEXING = new Progress() { + Progress INDEXING = new Progress() { @Override public Color getOkColor() { return INDEXING_OK_COLOR; diff --git a/platform/platform-api/src/com/intellij/ui/EditorNotificationPanel.java b/platform/platform-api/src/com/intellij/ui/EditorNotificationPanel.java index 4ad9c87ef258..3aeeb12e9a66 100644 --- a/platform/platform-api/src/com/intellij/ui/EditorNotificationPanel.java +++ b/platform/platform-api/src/com/intellij/ui/EditorNotificationPanel.java @@ -22,6 +22,7 @@ import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorBundle; import com.intellij.openapi.editor.colors.ColorKey; @@ -132,16 +133,24 @@ public class EditorNotificationPanel extends JPanel implements IntentionActionPr protected void executeAction(final String actionId) { final AnAction action = ActionManager.getInstance().getAction(actionId); - final AnActionEvent event = AnActionEvent.createFromAnAction(action, null, ActionPlaces.UNKNOWN, + final AnActionEvent event = AnActionEvent.createFromAnAction(action, null, getActionPlace(), DataManager.getInstance().getDataContext(this)); action.beforeActionPerformedUpdate(event); action.update(event); if (event.getPresentation().isEnabled() && event.getPresentation().isVisible()) { + ActionManagerEx actionManager = ActionManagerEx.getInstanceEx(); + actionManager.fireBeforeActionPerformed(action, event.getDataContext(), event); action.actionPerformed(event); + actionManager.fireAfterActionPerformed(action, event.getDataContext(), event); } } + @NotNull + protected String getActionPlace() { + return ActionPlaces.UNKNOWN; + } + @Nullable @Override public IntentionActionWithOptions getIntentionAction() { diff --git a/platform/platform-api/src/com/intellij/ui/JBCardLayout.java b/platform/platform-api/src/com/intellij/ui/JBCardLayout.java index aca9487c472c..1e1e4cef48e0 100644 --- a/platform/platform-api/src/com/intellij/ui/JBCardLayout.java +++ b/platform/platform-api/src/com/intellij/ui/JBCardLayout.java @@ -37,8 +37,8 @@ public class JBCardLayout extends CardLayout { public enum SwipeDirection {FORWARD, BACKWARD, AUTO} private final Map myMap = new LinkedHashMap<>(); - private final int mySwipeTime = 200;//default value, provide setter if need - private final int mySwipeSteps = 20;//default value, provide setter if need + private static final int mySwipeTime = 200;//default value, provide setter if need + private static final int mySwipeSteps = 20;//default value, provide setter if need private final Timer myTimer = UIUtil.createNamedTimer("CardLayoutTimer",Math.max(1, mySwipeTime / mySwipeSteps)); private Component mySwipeFrom = null; private Component mySwipeTo = null; diff --git a/platform/platform-api/src/com/intellij/ui/ListUtil.java b/platform/platform-api/src/com/intellij/ui/ListUtil.java index de942516d0fd..5492a49eb323 100644 --- a/platform/platform-api/src/com/intellij/ui/ListUtil.java +++ b/platform/platform-api/src/com/intellij/ui/ListUtil.java @@ -335,7 +335,7 @@ public class ListUtil { return listener; } - public static interface RemoveNotification { + public interface RemoveNotification { void itemsRemoved(List items); } @@ -350,7 +350,7 @@ public class ListUtil { return null; } - private static interface ListModelExtension { + private interface ListModelExtension { Object get(ModelType model, int index); void remove(ModelType model, int index); } diff --git a/platform/platform-api/src/com/intellij/ui/ReorderableListController.java b/platform/platform-api/src/com/intellij/ui/ReorderableListController.java index 5f6689939c8b..f610e8a053e6 100644 --- a/platform/platform-api/src/com/intellij/ui/ReorderableListController.java +++ b/platform/platform-api/src/com/intellij/ui/ReorderableListController.java @@ -196,7 +196,7 @@ public abstract class ReorderableListController { } } - static interface ActionBehaviour { + interface ActionBehaviour { T performAction(@NotNull AnActionEvent e); void updateAction(@NotNull AnActionEvent e); } diff --git a/platform/platform-api/src/com/intellij/ui/TableCellState.java b/platform/platform-api/src/com/intellij/ui/TableCellState.java index f7ee2a8af931..091907030221 100644 --- a/platform/platform-api/src/com/intellij/ui/TableCellState.java +++ b/platform/platform-api/src/com/intellij/ui/TableCellState.java @@ -15,9 +15,6 @@ */ package com.intellij.ui; -import com.intellij.util.ui.JBEmptyBorder; -import com.intellij.util.ui.UIUtil; - import javax.swing.*; import javax.swing.border.Border; import java.awt.*; @@ -42,15 +39,23 @@ public class TableCellState { myBackground = table.getBackground(); } - Border border = UIUtil.getTableFocusCellHighlightBorder(); if (hasFocus) { - myCellBorder = border; - if (table.isCellEditable(row, column)) { - myForeground = UIUtil.getTableFocusCellForeground(); - myBackground = UIUtil.getTableFocusCellBackground(); + Border border = null; + if (isSelected) { + border = UIManager.getBorder("Table.focusSelectedCellHighlightBorder"); } + if (border == null) { + border = UIManager.getBorder("Table.focusCellHighlightBorder"); + } + + myCellBorder = border; + + //if (table.isCellEditable(row, column)) { + // myForeground = UIUtil.getTableFocusCellForeground(); + // myBackground = UIUtil.getTableFocusCellBackground(); + //} } else { - myCellBorder = new JBEmptyBorder(border.getBorderInsets(null)); + myCellBorder = UIManager.getBorder("Table.cellNoFocusBorder"); } } diff --git a/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextField.java b/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextField.java index f1ed33116eae..391da221ae0d 100644 --- a/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextField.java +++ b/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextField.java @@ -60,8 +60,11 @@ public class ExtendableTextField extends JBTextField implements ExtendableTextCo @Override public void addExtension(@NotNull Extension extension) { - List extensions = new ArrayList<>(getExtensions()); - if (extensions.add(extension)) setExtensions(extensions); + if (!getExtensions().contains(extension)) { + List extensions = new ArrayList<>(getExtensions()); + extensions.add(extension); + setExtensions(extensions); + } } @Override diff --git a/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java b/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java index 006bc106b88a..8742723972f1 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java @@ -128,7 +128,7 @@ public class JBTabsImpl extends JComponent private boolean myPaintBlocked; private BufferedImage myImage; private IdeFocusManager myFocusManager; - private final boolean myAdjustBorders = true; + private static final boolean myAdjustBorders = true; boolean myAddNavigationGroup = true; diff --git a/platform/platform-impl/src/com/intellij/featureStatistics/fusCollectors/LifecycleUsageTriggerCollector.java b/platform/platform-impl/src/com/intellij/featureStatistics/fusCollectors/LifecycleUsageTriggerCollector.java index d71e40246473..4e4e4acbeeed 100644 --- a/platform/platform-impl/src/com/intellij/featureStatistics/fusCollectors/LifecycleUsageTriggerCollector.java +++ b/platform/platform-impl/src/com/intellij/featureStatistics/fusCollectors/LifecycleUsageTriggerCollector.java @@ -3,6 +3,8 @@ package com.intellij.featureStatistics.fusCollectors; import com.intellij.internal.statistic.eventLog.FeatureUsageData; import com.intellij.internal.statistic.service.fus.collectors.FUCounterUsageLogger; +import com.intellij.internal.statistic.utils.StatisticsUploadAssistant; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; @@ -14,7 +16,18 @@ public class LifecycleUsageTriggerCollector { private static final String LIFECYCLE = "lifecycle"; public static void onIdeStart() { - FUCounterUsageLogger.getInstance().logEvent(LIFECYCLE, "ide.start"); + final FeatureUsageData data = new FeatureUsageData().addData("eap", ApplicationManager.getApplication().isEAP()); + addIfTrue(data, "test", StatisticsUploadAssistant.isTestStatisticsEnabled()); + addIfTrue(data, "command_line", ApplicationManager.getApplication().isCommandLine()); + addIfTrue(data, "internal", ApplicationManager.getApplication().isInternal()); + addIfTrue(data, "headless", ApplicationManager.getApplication().isHeadlessEnvironment()); + FUCounterUsageLogger.getInstance().logEvent(LIFECYCLE, "ide.start", data); + } + + private static void addIfTrue(@NotNull FeatureUsageData data, @NotNull String key, boolean value) { + if (value) { + data.addData(key, value); + } } public static void onIdeClose(boolean restart) { diff --git a/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationManager.java b/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationManager.java index d38becfbb51e..93ff22ede233 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationManager.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationManager.java @@ -92,12 +92,6 @@ public class RecentLocationManager implements ProjectComponent { return item == null ? null : item.getPositionOffsetMarker(); } - @Nullable - EditorColorsScheme getColorScheme(@NotNull PlaceInfo placeInfo, boolean showChanged) { - PlaceInfoPersistentItem item = getMap(showChanged).get(placeInfo); - return item == null ? null : item.getScheme(); - } - private void subscribeOnExternalChange(@NotNull MessageBusConnection connection) { connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { @Override diff --git a/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationsAction.java b/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationsAction.java index 26c0337c688d..cf07ac1f46b8 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationsAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationsAction.java @@ -550,22 +550,12 @@ public class RecentLocationsAction extends AnAction { @NotNull Document document, @NotNull PlaceInfo placeInfo, @NotNull TextRange textRange) { - EditorColorsScheme colorsScheme = setupColorScheme(project, editor, placeInfo); + EditorColorsScheme colorsScheme = EditorColorsManager.getInstance().getGlobalScheme(); applySyntaxHighlighting(project, editor, document, colorsScheme, textRange, placeInfo); applyHighlightingPasses(project, editor, document, colorsScheme, textRange); } - @NotNull - private static EditorColorsScheme setupColorScheme(@NotNull Project project, @NotNull EditorEx editor, @NotNull PlaceInfo placeInfo) { - EditorColorsScheme colorsScheme = RecentLocationManager.getInstance(project).getColorScheme(placeInfo, showChanged(project)); - if (colorsScheme == null) { - colorsScheme = EditorColorsManager.getInstance().getGlobalScheme(); - } - editor.setColorsScheme(colorsScheme); - return colorsScheme; - } - private static void applySyntaxHighlighting(@NotNull Project project, @NotNull EditorEx editor, @NotNull Document document, diff --git a/platform/platform-impl/src/com/intellij/ide/actions/SaveAllAction.kt b/platform/platform-impl/src/com/intellij/ide/actions/SaveAllAction.kt index f22e7e10ecf4..81b429e1b65a 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/SaveAllAction.kt +++ b/platform/platform-impl/src/com/intellij/ide/actions/SaveAllAction.kt @@ -18,9 +18,11 @@ open class SaveAllAction : AnAction(), DumbAware { override fun actionPerformed(e: AnActionEvent) { CommonDataKeys.EDITOR.getData(e.dataContext)?.let(::stripSpacesFromCaretLines) + val project = CommonDataKeys.PROJECT.getData(e.dataContext) GlobalScope.launch(pooledThreadContext) { - saveDocumentsAndProjectsAndApp(onlyProject = CommonDataKeys.PROJECT.getData(e.dataContext), - isForceSavingAllSettings = true) + if (project == null || !project.isDisposed) { + saveDocumentsAndProjectsAndApp(onlyProject = project, isForceSavingAllSettings = true) + } } } } diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowMoveAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowMoveAction.java index f7f2280f1aa3..31e5b1300db8 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowMoveAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowMoveAction.java @@ -144,6 +144,11 @@ public class ToolWindowMoveAction extends DumbAwareAction { super(UIBundle.message("tool.window.move.to.action.group.name"), true); } + @Override + public boolean isDumbAware() { + return true; + } + @Override public void update(@NotNull AnActionEvent e) { if (!isInitialized) { diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowViewModeAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowViewModeAction.java index e9a4164d25d6..9b5d5bbb450d 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowViewModeAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowViewModeAction.java @@ -147,6 +147,11 @@ public class ToolWindowViewModeAction extends DumbAwareToggleAction { super(ActionsBundle.groupText("ViewMode"), true); } + @Override + public boolean isDumbAware() { + return true; + } + @Override public void update(@NotNull AnActionEvent e) { if (!isInitialized) { diff --git a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java index b8a5306a7e9b..f3eab64c4790 100644 --- a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java +++ b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java @@ -180,10 +180,9 @@ public class CustomizeIDEWizardDialog extends DialogWrapper implements ActionLis super.doOKAction(); } - @Nullable @Override - protected String getLoggedDialogId() { - return null; + protected boolean canRecordDialogId() { + return false; } private void initCurrentStep(boolean forward) { diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java index cf68206f1655..5cdd5310b6f1 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java @@ -2,6 +2,7 @@ package com.intellij.ide.plugins; import com.intellij.ide.IdeBundle; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.options.Configurable; @@ -9,17 +10,17 @@ import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; -import com.intellij.openapi.ui.ComponentValidator; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.popup.JBPopup; -import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.ui.cellvalidators.*; import com.intellij.openapi.updateSettings.impl.UpdateSettings; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.ui.AnimatedIcon; import com.intellij.ui.ColoredTableCellRenderer; import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.ToolbarDecorator; +import com.intellij.ui.components.fields.ExtendableTextField; import com.intellij.ui.table.JBTable; import com.intellij.util.io.URLUtil; import com.intellij.util.ui.ColumnInfo; @@ -33,8 +34,6 @@ import javax.swing.*; import javax.swing.border.Border; import javax.swing.event.ChangeEvent; import java.awt.*; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -48,6 +47,7 @@ public class PluginHostsConfigurable implements Configurable.NoScroll, Configura }; private final AnimatedIcon.Default myAnimatedIcon = new AnimatedIcon.Default(); + private final Disposable myDisposable = Disposer.newDisposable(); private final JBTable myTable = new JBTable(myModel) { @Override @@ -135,119 +135,51 @@ public class PluginHostsConfigurable implements Configurable.NoScroll, Configura myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - myTable.setDefaultRenderer(Object.class, new ColoredTableCellRenderer() { - final SimpleTextAttributes ERROR_ATTRIBUTES = - new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, DialogWrapper.ERROR_FOREGROUND_COLOR); - - @Override - protected void customizeCellRenderer(JTable table, @Nullable Object value, boolean selected, boolean hasFocus, int row, int column) { - if (row >= 0 && row < myModel.getRowCount()) { - UrlInfo info = myModel.getRowValue(row); - setBorder(null); - setForeground(selected ? table.getSelectionForeground() : table.getForeground()); - setBackground(selected ? table.getSelectionBackground() : table.getBackground()); - append(info.name, info.errorTooltip != null && !info.progress ? ERROR_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES); - } - } - - @Override - protected SimpleTextAttributes modifyAttributes(SimpleTextAttributes attributes) { - return attributes; - } - }); - - DefaultCellEditor editor = new DefaultCellEditor(new JTextField()); + ExtendableTextField cellEditor = new ExtendableTextField(); + DefaultCellEditor editor = new StatefulValidatingCellEditor(cellEditor, myDisposable). + withStateUpdater(vi -> ValidationUtils.setExtension(cellEditor, vi)); editor.setClickCountToStart(1); myTable.setDefaultEditor(Object.class, editor); - createValidatorHandler(); + myTable.setDefaultRenderer(Object.class, new ValidatingTableCellRendererWrapper(new ColoredTableCellRenderer() { + { setIpad(JBUI.emptyInsets());} + + @Override + protected void customizeCellRenderer(JTable table, @Nullable Object value, boolean selected, boolean hasFocus, int row, int column) { + if (row >= 0 && row < myModel.getRowCount()) { + UrlInfo info = myModel.getRowValue(row); + setForeground(selected ? table.getSelectionForeground() : table.getForeground()); + setBackground(selected ? table.getSelectionBackground() : table.getBackground()); + append(info.name, SimpleTextAttributes.REGULAR_ATTRIBUTES); + } + } + + @Override + protected SimpleTextAttributes modifyAttributes(SimpleTextAttributes attributes) { + return attributes; + } + }). + bindToEditorSize(cellEditor::getPreferredSize). + withCellValidator((value, row, column) -> { + if (row >= 0 && row < myModel.getRowCount()) { + UrlInfo info = myModel.getRowValue(row); + return info.errorTooltip == null || info.progress ? null : new ValidationInfo(info.errorTooltip); + } + else { + return null; + } + })); + + new CellTooltipManager(myDisposable). + withCellComponentProvider(CellComponentProvider.forTable(myTable)). + installOn(myTable); return ToolbarDecorator.createDecorator(myTable).disableUpDownActions().createPanel(); } - private void createValidatorHandler() { - MouseAdapter listener = new MouseAdapter() { - @Override - public void mouseEntered(MouseEvent e) { - showErrorPopup(e); - } - - @Override - public void mouseExited(MouseEvent event) { - if (!myTable.contains(event.getX(), event.getY()) || myTable.rowAtPoint(event.getPoint()) == myTable.getEditingRow()) { - hideErrorPopup(); - } - } - - @Override - public void mouseMoved(MouseEvent e) { - showErrorPopup(e); - } - }; - myTable.addMouseListener(listener); - myTable.addMouseMotionListener(listener); - } - - private JBPopup myErrorPopup; - private JLabel myErrorLabel; - - private void showErrorPopup(@NotNull MouseEvent event) { - int row = myTable.rowAtPoint(event.getPoint()); - if (row == -1 || row == myTable.getEditingRow()) { - hideErrorPopup(); - return; - } - - UrlInfo item = myModel.getItem(row); - if (item.progress || item.errorTooltip == null) { - hideErrorPopup(); - return; - } - - if (myErrorPopup != null && myErrorPopup.isVisible() && myErrorPopup.getContent().getParent() != null) { - myErrorLabel.setText(item.errorTooltip); - showErrorPopup(row, true); - return; - } - - hideErrorPopup(); - - myErrorLabel = new JLabel(item.errorTooltip); - myErrorLabel.setOpaque(true); - myErrorLabel.setBackground(JBUI.CurrentTheme.Validator.errorBackgroundColor()); - myErrorLabel.setBorder(ComponentValidator.getBorder()); - - myErrorPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(myErrorLabel, null) - .setBorderColor(JBUI.CurrentTheme.Validator.errorBorderColor()).setShowShadow(false).createPopup(); - - showErrorPopup(row, false); - } - - private void showErrorPopup(int row, boolean update) { - Rectangle cellRect = myTable.getCellRect(row, 0, false); - Point location = new Point(cellRect.x + JBUI.scale(40), cellRect.y - myErrorLabel.getPreferredSize().height - JBUI.scale(4)); - SwingUtilities.convertPointToScreen(location, myTable); - - if (update) { - myErrorPopup.pack(true, true); - myErrorPopup.setLocation(location); - } - else { - myErrorPopup.showInScreenCoordinates(myTable, location); - } - } - @Override public void disposeUIResources() { - hideErrorPopup(); - } - - private void hideErrorPopup() { - if (myErrorPopup != null) { - myErrorPopup.cancel(); - myErrorPopup = null; - myErrorLabel = null; - } + Disposer.dispose(myDisposable); } private void validateRepositories(@NotNull List urls) { diff --git a/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java index fdcd1b8df7cf..d844fd40a028 100644 --- a/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java @@ -149,7 +149,7 @@ public class StartupManagerImpl extends StartupManagerEx { } private void logActivityDuration(AtomicBoolean uiFreezeWarned, StartupActivity extension) { - long duration = TimeoutUtil.runAndGetExecutionTime(() -> extension.runActivity(myProject)); + long duration = TimeoutUtil.measureExecutionTime(() -> extension.runActivity(myProject)); Application app = ApplicationManager.getApplication(); if (duration > 100 && !app.isUnitTestMode()) { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaTableSelectedCellHighlightBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaTableSelectedCellHighlightBorder.java index 83f8777f1915..c62afbf1e859 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaTableSelectedCellHighlightBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaTableSelectedCellHighlightBorder.java @@ -33,7 +33,7 @@ public class DarculaTableSelectedCellHighlightBorder extends CompoundBorder impl } protected Border createInsideBorder() { - return JBUI.Borders.empty(3); + return JBUI.Borders.empty(2); } protected Color createFocusBorderColor() { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java index 04e1a85b1aba..8bfa6b441fc2 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java @@ -262,8 +262,8 @@ public class DarculaUIUtil { @Override public Insets getBorderInsets(Component c) { - return isTableCellEditor(c) || isCompact(c) ? JBUI.insets(2).asUIResource() : - isComboBoxEditor(c) ? JBUI.insets(2, 3).asUIResource() : JBUI.insets(5, 8).asUIResource(); + return isTableCellEditor(c) || isCompact(c) || isComboBoxEditor(c) ? + JBUI.insets(2, 3).asUIResource() : JBUI.insets(5, 8).asUIResource(); } } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties index e10cbdd8358e..9a6d9af1046c 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties @@ -64,7 +64,7 @@ TableHeaderUI=com.intellij.ide.ui.laf.darcula.DarculaTableHeaderUI Table.gridColor=2c2c2c Table.ascendingSortIcon=AllIcons.General.ArrowUp Table.descendingSortIcon=AllIcons.General.SplitDown -Table.cellNoFocusBorder=4,4,4,4 +Table.cellNoFocusBorder=3,3,3,3 Table.focusSelectedCellHighlightBorder=com.intellij.ide.ui.laf.darcula.DarculaTableSelectedCellHighlightBorder #just to suppress border painters diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java index 7c4cb93cf038..245bfc39abaf 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java @@ -119,8 +119,8 @@ public class DarculaEditorTextFieldBorder extends DarculaTextBorder implements V @Override public Insets getBorderInsets(Component c) { - return isTableCellEditor(c) || isCompact(c) ? JBUI.insets(2).asUIResource() : - isComboBoxEditor(c) ? JBUI.insets(2, 3).asUIResource() : JBUI.insets(6, 8).asUIResource(); + return isTableCellEditor(c) || isCompact(c) || isComboBoxEditor(c) ? + JBUI.insets(2, 3).asUIResource() : JBUI.insets(6, 8).asUIResource(); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextBorder.java index c89fa4bedef3..3ab1b20e12e3 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextBorder.java @@ -25,7 +25,7 @@ import static com.intellij.ide.ui.laf.darcula.DarculaUIUtil.*; public class DarculaTextBorder implements Border, UIResource, ErrorBorderCapable { @Override public Insets getBorderInsets(Component c) { - return JBUI.insets(isTableCellEditor(c) || isCompact(c) ? 2 : 3).asUIResource(); + return JBUI.insets(isTableCellEditor(c) || isCompact(c) ? 2 : 3, 3).asUIResource(); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTableSelectedCellHighlightBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTableSelectedCellHighlightBorder.java index c508e603c979..e92e81a3e267 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTableSelectedCellHighlightBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTableSelectedCellHighlightBorder.java @@ -9,6 +9,6 @@ import javax.swing.border.Border; public class WinIntelliJTableSelectedCellHighlightBorder extends DarculaTableSelectedCellHighlightBorder { @Override protected Border createInsideBorder() { - return JBUI.Borders.empty(2); + return JBUI.Borders.empty(2, 3, 2, 2); } } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextBorder.java index a6b2a05d2f7c..ca25020d3bce 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextBorder.java @@ -35,7 +35,9 @@ public class WinIntelliJTextBorder extends DarculaTextBorder { @Override public Insets getBorderInsets(Component c) { - return JBUI.insets(isTableCellEditor(c) || isCompact(c) ? 0 : 1).asUIResource(); + return isTableCellEditor(c) || isCompact(c) ? + JBUI.insets(1, 1, 1, 4).asUIResource() : + JBUI.insets(1).asUIResource(); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties index 35e13a1c189c..e703a742357a 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties @@ -60,7 +60,7 @@ Table.gridColor=dddddd Table.ascendingSortIcon=AllIcons.General.ArrowUp Table.descendingSortIcon=AllIcons.General.SplitDown Table.background=ffffff -Table.cellNoFocusBorder=4,4,4,4 +Table.cellNoFocusBorder=3,3,3,3 Table.focusSelectedCellHighlightBorder=com.intellij.ide.ui.laf.darcula.DarculaTableSelectedCellHighlightBorder #just to suppress border painters diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties index aa2c33cc8e29..0ea0a0166724 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties @@ -62,7 +62,7 @@ Table.gridColor=dddddd Table.ascendingSortIcon=AllIcons.General.ArrowUp Table.descendingSortIcon=AllIcons.General.SplitDown Table.background=ffffff -Table.cellNoFocusBorder=4,4,4,4 +Table.cellNoFocusBorder=3,4,3,3 Table.focusSelectedCellHighlightBorder=com.intellij.ide.ui.laf.intellij.WinIntelliJTableSelectedCellHighlightBorder LabelUI=com.intellij.ide.ui.laf.darcula.ui.DarculaLabelUI diff --git a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java index e36b582e8eae..417abb862ff2 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java @@ -47,7 +47,7 @@ public class SearchUtil { } private static void processConfigurables(Configurable[] configurables, Map> options) { - for (Configurable configurable : configurables) { + for (final Configurable configurable : configurables) { if (configurable instanceof SearchableConfigurable) { //ignore invisible root nodes //noinspection deprecation @@ -55,24 +55,29 @@ public class SearchUtil { continue; } + final SearchableConfigurable searchableConfigurable = (SearchableConfigurable) configurable; + Set configurableOptions = new TreeSet<>(); - options.put((SearchableConfigurable)configurable, configurableOptions); + options.put(searchableConfigurable, configurableOptions); + + for (TraverseUIHelper extension : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension.beforeConfigurable(searchableConfigurable, configurableOptions); if (configurable instanceof MasterDetails) { final MasterDetails md = (MasterDetails)configurable; md.initUi(); - processComponent(configurable, configurableOptions, md.getMaster()); - processComponent(configurable, configurableOptions, md.getDetails().getComponent()); + processComponent(searchableConfigurable, configurableOptions, md.getMaster()); + processComponent(searchableConfigurable, configurableOptions, md.getDetails().getComponent()); } else { - processComponent(configurable, configurableOptions, configurable.createComponent()); + processComponent(searchableConfigurable, configurableOptions, configurable.createComponent()); final Configurable unwrapped = unwrapConfigurable(configurable); if (unwrapped instanceof CompositeConfigurable) { //noinspection unchecked final List children = ((CompositeConfigurable)unwrapped).getConfigurables(); for (final UnnamedConfigurable child : children) { final Set childConfigurableOptions = new TreeSet<>(); - options.put(new SearchableConfigurableAdapter((SearchableConfigurable)configurable, child), childConfigurableOptions); + options.put(new SearchableConfigurableAdapter(searchableConfigurable, child), childConfigurableOptions); if (child instanceof SearchableConfigurable) { processUILabel(((SearchableConfigurable)child).getDisplayName(), childConfigurableOptions, null); @@ -86,6 +91,9 @@ public class SearchUtil { } } } + + for (TraverseUIHelper extension : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension.afterConfigurable(searchableConfigurable, configurableOptions); } } } @@ -108,10 +116,16 @@ public class SearchUtil { return configurable; } - private static void processComponent(Configurable configurable, Set configurableOptions, JComponent component) { + private static void processComponent(SearchableConfigurable configurable, Set configurableOptions, JComponent component) { if (component != null) { + for (TraverseUIHelper extension : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension.beforeComponent(configurable, component, configurableOptions); + processUILabel(configurable.getDisplayName(), configurableOptions, null); processComponent(component, configurableOptions, null); + + for (TraverseUIHelper extension : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension.afterComponent(configurable, component, configurableOptions); } } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/search/TraverseUIHelper.java b/platform/platform-impl/src/com/intellij/ide/ui/search/TraverseUIHelper.java new file mode 100644 index 000000000000..07a110f5d682 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/ui/search/TraverseUIHelper.java @@ -0,0 +1,49 @@ +package com.intellij.ide.ui.search; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.options.SearchableConfigurable; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.Map; +import java.util.Set; + +public interface TraverseUIHelper { + String EP_NAME = "com.intellij.search.traverseUiHelper"; + ExtensionPointName helperExtensionPoint = ExtensionPointName.create(EP_NAME); + + /** + * Invoked before indexing SearchableConfigurables + */ + default void beforeStart() {} + + /** + * Invoked after all configurables were traversed + */ + default void afterTraversal(@NotNull Map> options) {} + + /** + * Invoked after indexing all SearchableConfigurables and results are saved + */ + default void afterResultsAreSaved() {} + + /** + * Invoked before indexing a SearchableConfigurable + */ + default void beforeConfigurable(@NotNull SearchableConfigurable configurable, @NotNull Set options) {} + + /** + * Invoked after indexing a SearchableConfigurable + */ + default void afterConfigurable(@NotNull SearchableConfigurable configurable, @NotNull Set options) {} + + /** + * Invoked before indexing the root component of a SearchableConfigurable + */ + default void beforeComponent(@NotNull SearchableConfigurable configurable, @NotNull JComponent component, @NotNull Set options) {} + + /** + * Invoked after indexing the root component of a SearchableConfigurable + */ + default void afterComponent(@NotNull SearchableConfigurable configurable, @NotNull JComponent component, @NotNull Set options) {} +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/util/AppPropertiesComponentImpl.java b/platform/platform-impl/src/com/intellij/ide/util/AppPropertiesComponentImpl.java index 6b5c404c67dd..cb756b505a86 100644 --- a/platform/platform-impl/src/com/intellij/ide/util/AppPropertiesComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/util/AppPropertiesComponentImpl.java @@ -1,12 +1,13 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.util; import com.intellij.openapi.components.RoamingType; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.StoragePathMacros; @State(name = "PropertiesComponent", storages = { - @Storage(value = Storage.NOT_ROAMABLE_FILE, roamingType = RoamingType.DISABLED), + @Storage(value = StoragePathMacros.NOT_ROAMABLE_FILE, roamingType = RoamingType.DISABLED), @Storage(value = "options.xml", roamingType = RoamingType.DISABLED, deprecated = true) }) public class AppPropertiesComponentImpl extends PropertiesComponentImpl { diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/eventLog/EventLogConfiguration.kt b/platform/platform-impl/src/com/intellij/internal/statistic/eventLog/EventLogConfiguration.kt index 67323521b21b..c2466f9752e5 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/eventLog/EventLogConfiguration.kt +++ b/platform/platform-impl/src/com/intellij/internal/statistic/eventLog/EventLogConfiguration.kt @@ -17,7 +17,7 @@ import java.util.prefs.Preferences object EventLogConfiguration { private val LOG = Logger.getInstance(EventLogConfiguration::class.java) private const val SALT_PREFERENCE_KEY = "feature_usage_event_log_salt" - const val version: Int = 6 + const val version: Int = 7 val sessionId: String = UUID.randomUUID().toString().shortedUUID() diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/CounterUsageCollectorEP.java b/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/CounterUsageCollectorEP.java index 39aaba88dbb2..a6e6cc816493 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/CounterUsageCollectorEP.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/CounterUsageCollectorEP.java @@ -4,14 +4,24 @@ package com.intellij.internal.statistic.service.fus.collectors; import com.intellij.openapi.extensions.AbstractExtensionPointBean; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.util.xmlb.annotations.Attribute; +import org.jetbrains.annotations.Nullable; public class CounterUsageCollectorEP extends AbstractExtensionPointBean { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.statistics.counterUsagesCollector"); - @Attribute("group_id") + @Attribute("groupId") public String groupID; + @Deprecated + @Attribute("group_id") + public String legacyGroupID; + @Attribute("version") public int version; + + @Nullable + public String getGroupId() { + return groupID != null ? groupID : legacyGroupID; + } } diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/FUCounterUsageLogger.java b/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/FUCounterUsageLogger.java index 738ddf252c31..e27dec90342c 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/FUCounterUsageLogger.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/FUCounterUsageLogger.java @@ -8,6 +8,7 @@ import com.intellij.internal.statistic.eventLog.FeatureUsageGroup; import com.intellij.internal.statistic.eventLog.FeatureUsageLogger; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -48,7 +49,10 @@ public class FUCounterUsageLogger { } for (CounterUsageCollectorEP ep : CounterUsageCollectorEP.EP_NAME.getExtensionList()) { - register(new FeatureUsageGroup(ep.groupID, ep.version)); + final String id = ep.getGroupId(); + if (StringUtil.isNotEmpty(id)) { + register(new FeatureUsageGroup(id, ep.version)); + } } JobScheduler.getScheduler().scheduleWithFixedDelay( diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/utils/StatisticsUploadAssistant.java b/platform/platform-impl/src/com/intellij/internal/statistic/utils/StatisticsUploadAssistant.java index ace9675aee45..717fa7778c53 100755 --- a/platform/platform-impl/src/com/intellij/internal/statistic/utils/StatisticsUploadAssistant.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/utils/StatisticsUploadAssistant.java @@ -66,6 +66,10 @@ public class StatisticsUploadAssistant { return (settings != null && settings.isAllowed()) || Boolean.getBoolean(ENABLE_LOCAL_STATISTICS_WITHOUT_REPORT); } + public static boolean isTestStatisticsEnabled() { + return Boolean.getBoolean(ENABLE_LOCAL_STATISTICS_WITHOUT_REPORT); + } + public static void updateSentTime() { UsageStatisticsPersistenceComponent.getInstance().setSentTime(System.currentTimeMillis()); } diff --git a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java index d257d3d6cfff..e8f101ce35a8 100644 --- a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java +++ b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java @@ -1,6 +1,7 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.internal.ui; +import com.intellij.icons.AllIcons; import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ModalityState; @@ -9,12 +10,14 @@ import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.*; -import com.intellij.openapi.ui.panel.ComponentPanel; +import com.intellij.openapi.ui.cellvalidators.*; import com.intellij.openapi.ui.panel.ProgressPanel; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBTabbedPane; +import com.intellij.ui.components.fields.ExtendableTextComponent; +import com.intellij.ui.components.fields.ExtendableTextField; import com.intellij.ui.components.labels.DropDownLink; import com.intellij.ui.table.JBTable; import com.intellij.util.Alarm; @@ -30,6 +33,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import javax.swing.plaf.basic.BasicComboBoxEditor; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; @@ -38,6 +43,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import java.util.HashSet; +import java.util.function.BiFunction; public class ComponentPanelTestAction extends DumbAwareAction { private enum Placement { @@ -80,6 +86,10 @@ public class ComponentPanelTestAction extends DumbAwareAction { "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "abracadabra")); private static final String[] STRING_VALUES = { "One", "Two", "Three", "Four", "Five", "Six" }; + private static final SimpleTextAttributes WARNING_CELL_ATTRIBUTES = new SimpleTextAttributes(SimpleTextAttributes.STYLE_WAVED, null); + + private static final ValidationInfo NULL_VALUE_ERROR = new ValidationInfo("Null value"); + private static final ValidationInfo NAN_VALUE_ERROR = new ValidationInfo("Not a number"); private final Alarm myAlarm = new Alarm(getDisposable()); private ProgressTimerRequest progressTimerRequest; @@ -177,7 +187,7 @@ public class ComponentPanelTestAction extends DumbAwareAction { } else { return null; } - }).installOn(text1); + }).andRegisterOnDocumentListener(text1).installOn(text1); Dimension d = text1.getPreferredSize(); text1.setPreferredSize(new Dimension(JBUI.scale(100), d.height)); @@ -197,31 +207,11 @@ public class ComponentPanelTestAction extends DumbAwareAction { String tt = text2.getText(); return StringUtil.isEmpty(tt) || tt.length() < 5 ? new ValidationInfo("Message is too short.
Should contain at least 5 symbols.
Please check rules.", text2) : null; - }).andStartOnFocusLost().installOn(text2); + }).andStartOnFocusLost().andRegisterOnDocumentListener(text2).installOn(text2); gc.gridy++; topPanel.add(UI.PanelFactory.panel(text2).withLabel("&Path:").createPanel(), gc); - ComponentPanel cp = ComponentPanel.getComponentPanel(text2); - text1.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(@NotNull DocumentEvent e) { - String text = text1.getText(); - if (cp != null) { - cp.setCommentText(text); - } - - ComponentValidator.getInstance(text1).ifPresent(v -> v.revalidate()); - } - }); - - text2.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(@NotNull DocumentEvent e) { - ComponentValidator.getInstance(text2).ifPresent(v -> v.revalidate()); - } - }); - JCheckBox cb1 = new JCheckBox("Scroll tab layout"); cb1.addActionListener(e -> pane.setTabLayoutPolicy(cb1.isSelected() ? JTabbedPane.SCROLL_TAB_LAYOUT : JTabbedPane.WRAP_TAB_LAYOUT)); gc.gridy++; @@ -243,6 +233,18 @@ public class ComponentPanelTestAction extends DumbAwareAction { topPanel.add(UI.PanelFactory.panel(new JComboBox<>(STRING_VALUES)). withComment("Combobox comment").createPanel(), gc); + JBScrollPane pane = new JBScrollPane(createTable()); + pane.setPreferredSize(JBUI.size(400, 300)); + pane.putClientProperty(UIUtil.KEEP_BORDER_SIDES, SideBorder.ALL); + + BorderLayoutPanel mainPanel = JBUI.Panels.simplePanel(UI.PanelFactory.panel(pane). + withLabel("Table label:").moveLabelOnTop().withComment("Table comment").resizeY(true).createPanel()); + mainPanel.addToTop(topPanel); + + return mainPanel; + } + + private JComponent createTable() { String[] columns = { "First column", "Second column" }; String[][] data = {{"one", "1"}, {"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}, {"six", "6"}, {"seven", "7"}, {"eight", "8"}, {"nine", "9"}, {"ten", "10"}, {"eleven", "11"}, @@ -261,48 +263,91 @@ public class ComponentPanelTestAction extends DumbAwareAction { public boolean isCellEditable(int row, int column) { return true; } @Override public void setValueAt(Object value, int row, int col) { - if (col == 0 && ALLOWED_VALUES.contains(value.toString()) || col == 1) { + if (col == 0 || col == 1) { data[row][col] = value.toString(); fireTableCellUpdated(row, col); } } }); - JTextField cellEditor = new JTextField(); + HyperlinkListener hyperlinkListener = e -> { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + System.out.println("Table cell tooltip link clicked. Desc = " + e.getDescription()); + } + }; + + BiFunction validationInfoGenerator = (text, component) -> + new ValidationInfo("Illegal value: " + text + "
Please check rules.", component); + + // Install custom tooltip manager for displaying error/warning tooltips + new CellTooltipManager(getDisposable()). + withCellComponentProvider(CellComponentProvider.forTable(table)). + withHyperlinkListener(hyperlinkListener).installOn(table); + + // Configure left column + ExtendableTextField cellEditor = new ExtendableTextField(); + ExtendableTextComponent.Extension browseExtension = + ExtendableTextComponent.Extension.create(AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, + "Open file", () -> System.out.println("Table browse clicked")); + cellEditor.addExtension(browseExtension); cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE); - cellEditor.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(@NotNull DocumentEvent e) { - Object op = ALLOWED_VALUES.contains(cellEditor.getText()) ? null : "error"; - cellEditor.putClientProperty("JComponent.outline", op); - } - }); + new ComponentValidator(getDisposable()).withValidator(() -> { + boolean isAllowed = ALLOWED_VALUES.contains(cellEditor.getText()); + ValidationUtils.setExtension(cellEditor, ValidationUtils.ERROR_EXTENSION, !isAllowed); + return isAllowed ? null : validationInfoGenerator.apply(cellEditor.getText(), cellEditor); + }).withHyperlinkListener(hyperlinkListener). + andRegisterOnDocumentListener(cellEditor). + installOn(cellEditor); - TableColumn col0 = table.getColumnModel().getColumn(0); - col0.setCellEditor(new DefaultCellEditor(cellEditor)); - col0.setCellRenderer(new DefaultTableCellRenderer() { - @Override - public Dimension getPreferredSize() { - Dimension size = super.getPreferredSize(); - Dimension editorSize = cellEditor.getPreferredSize(); - size.height = Math.max(size.height, editorSize.height); - return size; - } - }); + TableColumn col = table.getColumnModel().getColumn(0); + col.setCellEditor(new DefaultCellEditor(cellEditor)); + col.setCellRenderer(new ValidatingTableCellRendererWrapper(new DefaultTableCellRenderer()). + bindToEditorSize(cellEditor::getPreferredSize). + withCellValidator((value, row, column) -> + value == null ? new ValidationInfo("Null value") : + ALLOWED_VALUES.contains(value.toString()) ? null : + validationInfoGenerator.apply(value.toString(), null))); + // Configure right column JComboBox rightEditor = new ComboBox<>(Arrays.stream(data).map(i -> Integer.valueOf(i[1])).toArray(Integer[]::new)); - table.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(rightEditor)); + col = table.getColumnModel().getColumn(1); - JBScrollPane pane = new JBScrollPane(table); - pane.setPreferredSize(JBUI.size(400, 300)); - pane.putClientProperty(UIUtil.KEEP_BORDER_SIDES, SideBorder.ALL); + col.setCellEditor(new StatefulValidatingCellEditor(rightEditor, getDisposable())); + col.setCellRenderer(new ValidatingTableCellRendererWrapper(new ColoredTableCellRenderer() { - BorderLayoutPanel mainPanel = JBUI.Panels.simplePanel(UI.PanelFactory.panel(pane). - withLabel("Table label:").moveLabelOnTop().withComment("Table comment").resizeY(true).createPanel()); - mainPanel.addToTop(topPanel); + { setIpad(JBUI.emptyInsets()); } // Reset standard pads - return mainPanel; + @Override + protected void customizeCellRenderer(JTable table, @Nullable Object value, boolean selected, + boolean hasFocus, int row, int column) { + if (value == null) { + append("No data", SimpleTextAttributes.ERROR_ATTRIBUTES); + } + else { + try { + int iv = Integer.parseInt(value.toString()); + append("value ", SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES); + append(value.toString(), iv <= 8 ? SimpleTextAttributes.REGULAR_ATTRIBUTES : WARNING_CELL_ATTRIBUTES); + } catch (NumberFormatException nfe) { + append(value.toString(), SimpleTextAttributes.ERROR_ATTRIBUTES); + } + } + } + }).bindToEditorSize(rightEditor::getPreferredSize). + withCellValidator((value, row, column) -> { + if (value == null) return NULL_VALUE_ERROR; + else { + try { + int iv = Integer.parseInt(value.toString()); + return iv <= 8 ? null : new ValidationInfo("Value " + value.toString() + " is not preferred").asWarning(); + } catch (NumberFormatException nfe) { + return NAN_VALUE_ERROR; + } + } + })); + + return table; } private JComponent createComponentGridPanel() { @@ -327,11 +372,11 @@ public class ComponentPanelTestAction extends DumbAwareAction { withLabel("&Host:").withComment("Host comment")). add(UI.PanelFactory.panel(new JComboBox<>(new String[]{"HTTP", "HTTPS", "FTP", "SSL"})). - withLabel("P&rotocol:").withComment("Protocol comment").withTooltip("Protocol selection"). + withLabel("P&rotocol:").withTooltip("Protocol selection"). withTooltipLink("Check here for more info", ()-> System.out.println("More info"))). add(UI.PanelFactory.panel(new ComponentWithBrowseButton<>(new JTextField(), (e) -> System.out.println("Browse for text"))). - withLabel("&Text field:").withComment("Text field comment")). + withLabel("&Text field:").withComment("Text field comment with link")). add(UI.PanelFactory.panel(cbb). withLabel("&Combobox selection:")). @@ -421,6 +466,23 @@ public class ComponentPanelTestAction extends DumbAwareAction { .withValidator(() -> comboBox.getSelectedIndex() % 2 == 0 ? new ValidationInfo("Can't select odd items", comboBox) : null) .installOn(comboBox); + // Extendable ComboBox + ExtendableTextComponent.Extension browseExtension = + ExtendableTextComponent.Extension.create(AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, + "Open file", () -> System.out.println("Browse file clicked")); + + ComboBox eComboBox = new ComboBox<>(STRING_VALUES); + eComboBox.setEditable(true); + eComboBox.setEditor(new BasicComboBoxEditor(){ + @Override + protected JTextField createEditorComponent() { + ExtendableTextField ecbEditor = new ExtendableTextField(); + ecbEditor.addExtension(browseExtension); + ecbEditor.setBorder(null); + return ecbEditor; + } + }); + // Panels factory return UI.PanelFactory.grid(). add(UI.PanelFactory.panel(tfbb). @@ -432,6 +494,9 @@ public class ComponentPanelTestAction extends DumbAwareAction { add(UI.PanelFactory.panel(comboBox). withLabel("&ComboBoxEditorTextField:").withComment("EditorComboBox editor")). + add(UI.PanelFactory.panel(eComboBox). + withLabel("ComboBox &extendable:").withComment("ComboBox with ExtendableTextEditor")). + createPanel(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java b/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java index 4460b716915a..5cd2427db024 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java @@ -6,7 +6,7 @@ import com.intellij.ide.cloudConfig.CloudConfigProvider; import com.intellij.ide.highlighter.ArchiveFileType; import com.intellij.ide.startup.StartupActionScriptManager; import com.intellij.idea.Main; -import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.StoragePathMacros; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; @@ -44,7 +44,7 @@ public class ConfigImportHelper { private static final String CONFIG = "config"; private static final String[] OPTIONS = { - OPTIONS_DIRECTORY + '/' + Storage.NOT_ROAMABLE_FILE, + OPTIONS_DIRECTORY + '/' + StoragePathMacros.NOT_ROAMABLE_FILE, OPTIONS_DIRECTORY + '/' + IDE_GENERAL_XML, OPTIONS_DIRECTORY + "/options.xml"}; private static final String BIN = "bin"; diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/NonBlockingReadActionImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/NonBlockingReadActionImpl.java index eb12721dbf71..600357a2cd61 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/NonBlockingReadActionImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/NonBlockingReadActionImpl.java @@ -1,9 +1,12 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.application.impl; +import com.google.common.annotations.VisibleForTesting; +import com.intellij.diagnostic.ThreadDumper; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.NonBlockingReadAction; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; @@ -12,26 +15,35 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.util.concurrency.Semaphore; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import org.jetbrains.concurrency.AsyncPromise; import org.jetbrains.concurrency.CancellablePromise; import org.jetbrains.concurrency.Promises; +import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.BooleanSupplier; import java.util.function.Consumer; /** * @author peter */ -class NonBlockingReadActionImpl implements NonBlockingReadAction { +@VisibleForTesting +public class NonBlockingReadActionImpl implements NonBlockingReadAction { private final @Nullable Pair> myEdtFinish; private final @Nullable DumbService myRequireSmartMode; //todo a more pluggable constraint API private final BooleanSupplier myExpireCondition; private final Callable myComputation; + private static final Set> ourTasks = ContainerUtil.newConcurrentSet(); + NonBlockingReadActionImpl(@Nullable Pair> edtFinish, @Nullable DumbService requireSmartMode, @NotNull BooleanSupplier expireCondition, @@ -61,6 +73,10 @@ class NonBlockingReadActionImpl implements NonBlockingReadAction { public CancellablePromise submit(@NotNull Executor backgroundThreadExecutor) { AsyncPromise promise = new AsyncPromise<>(); new Submission(promise, backgroundThreadExecutor).transferToBgThread(); + if (ApplicationManager.getApplication().isUnitTestMode()) { + ourTasks.add(promise); + promise.onProcessed(__ -> ourTasks.remove(promise)); + } return promise; } @@ -167,4 +183,45 @@ class NonBlockingReadActionImpl implements NonBlockingReadAction { } } + + @TestOnly + public static void cancelAllTasks() { + while (!ourTasks.isEmpty()) { + for (CancellablePromise task : ourTasks) { + task.cancel(); + } + WriteAction.run(() -> {}); // let background threads complete + } + } + + @TestOnly + public static void completeAsyncTasks() { + assert !ApplicationManager.getApplication().isWriteAccessAllowed(); + for (CancellablePromise task : ourTasks) { + waitForTask(task); + } + } + + @TestOnly + private static void waitForTask(CancellablePromise task) { + int iteration = 0; + while (!task.isDone() && iteration++ < 60_000) { + UIUtil.dispatchAllInvocationEvents(); + try { + task.blockingGet(1, TimeUnit.MILLISECONDS); + return; + } + catch (TimeoutException ignore) { + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + if (!task.isDone()) { + //noinspection UseOfSystemOutOrSystemErr + System.err.println(ThreadDumper.dumpThreadsToString()); + throw new AssertionError("Too long async task"); + } + } + } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index 43bc0de4324e..8295c8f3d836 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -1739,7 +1739,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse : renderer.getClickAction(); } if (clickAction != null) { - performAction(clickAction, e, "ICON_NAVIGATION", myEditor.getDataContext()); + performAction(clickAction, e, ActionPlaces.EDITOR_GUTTER, myEditor.getDataContext()); repaint(); e.consume(); } @@ -1959,7 +1959,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse if (renderer != null) { AnAction rightButtonAction = renderer.getRightButtonClickAction(); if (rightButtonAction != null) { - performAction(rightButtonAction, e, "ICON_NAVIGATION_SECONDARY_BUTTON", myEditor.getDataContext()); + performAction(rightButtonAction, e, ActionPlaces.EDITOR_GUTTER_POPUP, myEditor.getDataContext()); e.consume(); } else { 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 8621f8faa73f..275ee01e8fa0 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 @@ -698,6 +698,8 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis private static boolean isOpenInNewWindow() { AWTEvent event = IdeEventQueue.getInstance().getTrueCurrentEvent(); + // openFile... methods can be called several times in a row with the same InputEvent but we should open just one new window in this case + if (event instanceof InputEvent && ((InputEvent)event).isConsumed()) return false; // Shift was used while clicking if (event instanceof MouseEvent && @@ -705,14 +707,23 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis (event.getID() == MouseEvent.MOUSE_CLICKED || event.getID() == MouseEvent.MOUSE_PRESSED || event.getID() == MouseEvent.MOUSE_RELEASED)) { + ((MouseEvent)event).consume(); return true; } if (event instanceof KeyEvent) { KeyEvent ke = (KeyEvent)event; - Keymap keymap = KeymapManager.getInstance().getActiveKeymap(); + KeymapManager keymapManager = KeymapManager.getInstance(); + if (keymapManager == null) { + return false; + } + Keymap keymap = keymapManager.getActiveKeymap(); String[] ids = keymap.getActionIds(KeyStroke.getKeyStroke(ke.getKeyCode(), ke.getModifiers())); - return Arrays.asList(ids).contains("OpenElementInNewWindow"); + boolean inNewWindow = Arrays.asList(ids).contains("OpenElementInNewWindow"); + if (inNewWindow) { + ke.consume(); + } + return inNewWindow; } return false; diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java index c950a9ef4b29..afb831c46bd0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java @@ -25,6 +25,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; +import java.util.function.Predicate; public class AsyncEditorLoader { private static final ExecutorService ourExecutor = AppExecutorUtil.createBoundedApplicationPoolExecutor("AsyncEditorLoader Pool", 2); @@ -116,10 +117,9 @@ public class AsyncEditorLoader { */ private LoadingProgress scheduleLoading() { CompletableFuture continuationFuture = new CompletableFuture<>(); - Document document = myEditor.getDocument(); Future totalProgressFuture = ourExecutor.submit(() -> { while (!myEditorComponent.isDisposed() && !isDone()) { - LoadEditorResult result = tryLoadEditor(document); + LoadEditorResult result = tryLoadEditor(); if (result != null) { continuationFuture.complete(result.continuation); invokeAndWait(() -> { @@ -127,7 +127,7 @@ public class AsyncEditorLoader { // it might happen when the caller already finished the loading manually through `continuationFuture` return; } - if ((myTooLongIndicator.isCanceled() || isCommitted()) && result.docStamp == document.getModificationStamp()) { + if ((myTooLongIndicator.isCanceled() || isCommitted()) && result.continuationValidator.test(myEditor.getDocument())) { loadingFinished(result.continuation); } }); @@ -146,24 +146,21 @@ public class AsyncEditorLoader { return myLoadingFinished.isDone(); } - private static class LoadEditorResult { - final long docStamp; + static class LoadEditorResult { + @NotNull final Predicate continuationValidator; @NotNull final Runnable continuation; - private LoadEditorResult(long docStamp, @NotNull Runnable continuation) { - this.docStamp = docStamp; + LoadEditorResult(@NotNull Predicate continuationValidator, @NotNull Runnable continuation) { + this.continuationValidator = continuationValidator; this.continuation = continuation; } } @Nullable - private LoadEditorResult tryLoadEditor(@NotNull Document document) { + private LoadEditorResult tryLoadEditor() { Ref ref = Ref.create(); - Runnable loadingRunnable = () -> { - Runnable continuation = - myProject.isDisposed() ? EmptyRunnable.INSTANCE : myTextEditor.loadEditorInBackground(); - ref.set(new LoadEditorResult(document.getModificationStamp(), continuation)); - }; + Runnable loadingRunnable = () -> ref.set(myProject.isDisposed() ? new LoadEditorResult(document -> true, EmptyRunnable.INSTANCE) + : myTextEditor.loadEditorInBackground()); if (!myTooLongIndicator.isCanceled()) { ProgressIndicatorUtils.runWithWriteActionPriority( () -> PsiDocumentManager.getInstance(myProject).commitAndRunReadAction(loadingRunnable), diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncHighlighterUpdater.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncHighlighterUpdater.java index 60d28f761ffc..cbc02bf87f34 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncHighlighterUpdater.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncHighlighterUpdater.java @@ -15,9 +15,9 @@ */ package com.intellij.openapi.fileEditor.impl.text; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.application.impl.NonBlockingReadActionImpl; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.highlighter.EditorHighlighter; @@ -26,15 +26,12 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.concurrency.AppExecutorUtil; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; import org.jetbrains.concurrency.CancellablePromise; import java.util.Map; import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; /** * @author peter @@ -66,26 +63,7 @@ public class AsyncHighlighterUpdater { @TestOnly public static void completeAsyncTasks() { - assert !ApplicationManager.getApplication().isWriteAccessAllowed(); - ApplicationManager.getApplication().invokeAndWait(() -> ourHighlighterFutures.values().forEach(AsyncHighlighterUpdater::waitForFuture)); - UIUtil.dispatchAllInvocationEvents(); + NonBlockingReadActionImpl.completeAsyncTasks(); } - @TestOnly - private static void waitForFuture(CancellablePromise future) { - int iteration = 0; - while (!future.isDone() && iteration++ < 1000) { - UIUtil.dispatchAllInvocationEvents(); - try { - future.blockingGet(10, TimeUnit.MILLISECONDS); - return; - } - catch (TimeoutException ignore) { - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - assert future.isDone() : "Too long async highlighter"; - } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java index 8f8e746094d1..94a8b64bdd2c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java @@ -70,18 +70,18 @@ public class TextEditorImpl extends UserDataHolderBase implements TextEditor { * @return a continuation to be called in EDT */ @NotNull - protected Runnable loadEditorInBackground() { + protected AsyncEditorLoader.LoadEditorResult loadEditorInBackground() { EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme(); EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(myFile, scheme, myProject); EditorEx editor = (EditorEx)getEditor(); highlighter.setText(editor.getDocument().getImmutableCharSequence()); long stamp = editor.getDocument().getModificationStamp(); Language language = getDocumentLanguage(editor); - return () -> { - LOG.assertTrue(stamp == editor.getDocument().getModificationStamp()); - editor.getSettings().setLanguage(language); - editor.setHighlighter(highlighter); - }; + return new AsyncEditorLoader.LoadEditorResult(document -> stamp == document.getModificationStamp(), + () -> { + editor.getSettings().setLanguage(language); + editor.setHighlighter(highlighter); + }); } @Nullable diff --git a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java index afa44d86da2a..ac31d54967f9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java @@ -2,6 +2,7 @@ package com.intellij.openapi.project; import com.google.common.annotations.VisibleForTesting; +import com.intellij.diagnostic.ThreadDumper; import com.intellij.ide.IdeBundle; import com.intellij.ide.file.BatchFileChangeListener; import com.intellij.openapi.Disposable; @@ -454,6 +455,7 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica return; } while (isDumb()) { + assertState(State.SCHEDULED_TASKS); showModalProgress(); } } @@ -461,22 +463,34 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica private void showModalProgress() { NoAccessDuringPsiEvents.checkCallContext(); try { - ((ApplicationImpl)ApplicationManager.getApplication()).executeSuspendingWriteAction(myProject, IdeBundle.message("progress.indexing"), () -> - runBackgroundProcess(ProgressManager.getInstance().getProgressIndicator())); + ((ApplicationImpl)ApplicationManager.getApplication()).executeSuspendingWriteAction(myProject, IdeBundle.message("progress.indexing"), () -> { + assertState(State.SCHEDULED_TASKS); + runBackgroundProcess(ProgressManager.getInstance().getProgressIndicator()); + assertState(State.SMART, State.WAITING_FOR_FINISH); + }); + assertState(State.SMART, State.WAITING_FOR_FINISH); } finally { if (myState.get() != State.SMART) { - assertWeAreWaitingToFinish(); + assertState(State.WAITING_FOR_FINISH); updateFinished(); + assertState(State.SMART, State.SCHEDULED_TASKS); } } } - private void assertWeAreWaitingToFinish() { - final State state = myState.get(); - if (state != State.WAITING_FOR_FINISH) { - Attachment[] attachments = myDumbEnterTrace != null ? new Attachment[]{new Attachment("indexingStart", myDumbEnterTrace)} : Attachment.EMPTY_ARRAY; - throw new RuntimeExceptionWithAttachments(state.toString(), attachments); + private void assertState(State... expected) { + State state = myState.get(); + List expectedList = Arrays.asList(expected); + if (!expectedList.contains(state)) { + List attachments = new ArrayList<>(); + if (myDumbEnterTrace != null) { + attachments.add(new Attachment("indexingStart", myDumbEnterTrace)); + } + attachments.add(new Attachment("threadDump.txt", ThreadDumper.dumpThreadsToString())); + throw new RuntimeExceptionWithAttachments("Internal error, please include thread dump attachment. " + + "Expected " + expectedList + ", but was " + state.toString(), + attachments.toArray(Attachment.EMPTY_ARRAY)); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/project/NoAccessDuringPsiEvents.java b/platform/platform-impl/src/com/intellij/openapi/project/NoAccessDuringPsiEvents.java index b96aed725ee2..f492fb74479f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/NoAccessDuringPsiEvents.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/NoAccessDuringPsiEvents.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.project; +import com.intellij.ProjectTopics; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -44,6 +45,8 @@ public class NoAccessDuringPsiEvents { if (!application.isWriteAccessAllowed()) return false; MessageBus bus = application.getMessageBus(); - return bus.hasUndeliveredEvents(VirtualFileManager.VFS_CHANGES) || bus.hasUndeliveredEvents(PsiModificationTracker.TOPIC); + return bus.hasUndeliveredEvents(VirtualFileManager.VFS_CHANGES) || + bus.hasUndeliveredEvents(PsiModificationTracker.TOPIC) || + bus.hasUndeliveredEvents(ProjectTopics.PROJECT_ROOTS); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index b659d65fabc6..a62ad55cd976 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -267,7 +267,8 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { final String realName = delegate.getCanonicallyCasedName(fake); boolean isDirectory = attributes.isDirectory(); boolean isEmptyDirectory = isDirectory && !delegate.hasChildren(fake); - final VFileCreateEvent event = new VFileCreateEvent(null, this, realName, isDirectory, attributes, true, isEmptyDirectory); + String symlinkTarget = attributes.isSymLink() ? delegate.resolveSymLink(fake) : null; + VFileCreateEvent event = new VFileCreateEvent(null, this, realName, isDirectory, attributes, symlinkTarget, true, isEmptyDirectory); RefreshQueue.getInstance().processSingleEvent(event); return findChild(realName); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java index 4911e9cd9659..f009f9835ad5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java @@ -58,6 +58,7 @@ public class FSRecords { static final String VFS_FILES_EXTENSION = System.getProperty("idea.vfs.files.extension", ".dat"); private static final boolean ourStoreRootsSeparately = SystemProperties.getBooleanProperty("idea.store.roots.separately", false); + //TODO[anyone] when bumping the version, please delete `ourSymlinkTargetAttr_old` and use it's value for `ourSymlinkTargetAttr` private static final int VERSION = 22 + (weHaveContentHashes ? 0x10:0) + (IOUtil.ourByteBuffersUseNativeByteOrder ? 0x37:0) + 31 + (bulkAttrReadSupport ? 0x27:0) + (inlineAttributes ? 0x31 : 0) + (ourStoreRootsSeparately ? 0x63 : 0) + @@ -97,7 +98,8 @@ public class FSRecords { private static final int CORRUPTED_MAGIC = 0xabcf7f7f; private static final FileAttribute ourChildrenAttr = new FileAttribute("FsRecords.DIRECTORY_CHILDREN"); - private static final FileAttribute ourSymlinkTargetAttr = new FileAttribute("FsRecords.SYMLINK_TARGET"); + private static final FileAttribute ourSymlinkTargetAttr = new FileAttribute("FsRecords.SYMLINK_TARGET_2"); + private static final FileAttribute ourSymlinkTargetAttr_old = new FileAttribute("FsRecords.SYMLINK_TARGET"); private static final ReentrantReadWriteLock lock; private static final ReentrantReadWriteLock.ReadLock r; @@ -984,8 +986,12 @@ public class FSRecords { static @Nullable String readSymlinkTarget(int id) { return readAndHandleErrors(() -> { try (DataInputStream stream = readAttribute(id, ourSymlinkTargetAttr)) { - return stream != null ? StringUtil.nullize(stream.readUTF()) : null; + if (stream != null) return StringUtil.nullize(IOUtil.readUTF(stream)); } + try (DataInputStream stream = readAttribute(id, ourSymlinkTargetAttr_old)) { + if (stream != null) return StringUtil.nullize(stream.readUTF()); + } + return null; }); } @@ -993,7 +999,7 @@ public class FSRecords { writeAndHandleErrors(() -> { DbConnection.markDirty(); try (DataOutputStream stream = writeAttribute(id, ourSymlinkTargetAttr)) { - stream.writeUTF(StringUtil.notNullize(symlinkTarget)); + IOUtil.writeUTF(stream, StringUtil.notNullize(symlinkTarget)); } }); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/LocalFileSystemRefreshWorker.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/LocalFileSystemRefreshWorker.java index 5644b19c73ab..323e722089e4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/LocalFileSystemRefreshWorker.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/LocalFileSystemRefreshWorker.java @@ -272,7 +272,8 @@ class LocalFileSystemRefreshWorker { if (child == null) { // new file is created VirtualFile parent = myFileOrDir.isDirectory() ? myFileOrDir : myFileOrDir.getParent(); - myHelper.scheduleCreation(parent, name, file, convert(file, attrs)); + String symlinkTarget = attrs.isSymbolicLink() ? file.toRealPath().toString() : null; + myHelper.scheduleCreation(parent, name, file, convert(file, attrs), symlinkTarget); return FileVisitResult.CONTINUE; } @@ -300,7 +301,8 @@ class LocalFileSystemRefreshWorker { oldIsSpecial != isSpecial) { // symlink or directory or special changed myHelper.scheduleDeletion(child); VirtualFile parent = myFileOrDir.isDirectory() ? myFileOrDir : myFileOrDir.getParent(); - myHelper.scheduleCreation(parent, child.getName(), file, convert(file, attrs)); + String symlinkTarget = isLink ? file.toRealPath().toString() : null; + myHelper.scheduleCreation(parent, child.getName(), file, convert(file, attrs), symlinkTarget); // ignore everything else child.markClean(); return FileVisitResult.CONTINUE; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java index 5c93444f3d59..2324bb3224d3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java @@ -179,7 +179,7 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis nameIds.add(nameId); } for (String newName : toAdd) { - Pair childData = getChildData(null, file, newName, fs); + Pair childData = getChildData(fs, file, newName, null, null); if (childData != null) { int childId = makeChildRecord(id, newName, childData, fs); childrenIds.add(childId); @@ -387,7 +387,7 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis if (namesEqual(fs, childName, FSRecords.getNameSequence(childId))) return childId; } - Pair childData = getChildData(null, parent, childName, fs); + Pair childData = getChildData(fs, parent, childName, null, null); if (childData != null) { int childId = makeChildRecord(parentId, childName, childData, fs); FSRecords.updateList(parentId, ArrayUtil.append(children, childId)); @@ -426,7 +426,7 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis @Override public VirtualFile createChildDirectory(Object requestor, @NotNull VirtualFile parent, @NotNull String dir) throws IOException { getDelegate(parent).createChildDirectory(requestor, parent, dir); - processEvent(new VFileCreateEvent(requestor, parent, dir, true, null, false, true)); + processEvent(new VFileCreateEvent(requestor, parent, dir, true, null, null, false, true)); final VirtualFile child = parent.findChild(dir); if (child == null) { @@ -439,7 +439,7 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis @Override public VirtualFile createChildFile(Object requestor, @NotNull VirtualFile parent, @NotNull String file) throws IOException { getDelegate(parent).createChildFile(requestor, parent, file); - processEvent(new VFileCreateEvent(requestor, parent, file, false, null, false, false)); + processEvent(new VFileCreateEvent(requestor, parent, file, false, null, null, false, false)); final VirtualFile child = parent.findChild(file); if (child == null) { @@ -967,7 +967,7 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis for (VFileCreateEvent createEvent : createEvents) { createEvent.resetCache(); String name = createEvent.getChildName(); - Pair childData = getChildData(createEvent.getAttributes(), parent, name, delegate); + Pair childData = getChildData(delegate, parent, name, createEvent.getAttributes(), createEvent.getSymlinkTarget()); if (childData != null) { int childId = makeChildRecord(parentId, name, childData, delegate); childrenAdded.add(new ChildInfo(childId, name, childData.first, createEvent.isEmptyDirectory())); @@ -1129,8 +1129,8 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis } try { if (event instanceof VFileCreateEvent) { - final VFileCreateEvent createEvent = (VFileCreateEvent)event; - executeCreateChild(createEvent.getParent(), createEvent.getChildName(), createEvent.getAttributes(), createEvent.isEmptyDirectory()); + VFileCreateEvent ce = (VFileCreateEvent)event; + executeCreateChild(ce.getParent(), ce.getChildName(), ce.getAttributes(), ce.getSymlinkTarget(), ce.isEmptyDirectory()); } else if (event instanceof VFileDeleteEvent) { final VFileDeleteEvent deleteEvent = (VFileDeleteEvent)event; @@ -1152,8 +1152,8 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis executeTouch(file, contentUpdateEvent.isFromRefresh(), contentUpdateEvent.getModificationStamp(), length, timestamp); } else if (event instanceof VFileCopyEvent) { - final VFileCopyEvent copyEvent = (VFileCopyEvent)event; - executeCreateChild(copyEvent.getNewParent(), copyEvent.getNewChildName(), null, copyEvent.getFile().getChildren().length == 0); + VFileCopyEvent ce = (VFileCopyEvent)event; + executeCreateChild(ce.getNewParent(), ce.getNewChildName(), null, null, ce.getFile().getChildren().length == 0); } else if (event instanceof VFileMoveEvent) { final VFileMoveEvent moveEvent = (VFileMoveEvent)event; @@ -1199,10 +1199,11 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis private void executeCreateChild(@NotNull VirtualFile parent, @NotNull String name, @Nullable FileAttributes attributes, + @Nullable String symlinkTarget, boolean isEmptyDirectory) { NewVirtualFileSystem delegate = getDelegate(parent); int parentId = getFileId(parent); - Pair childData = getChildData(attributes, parent, name, delegate); + Pair childData = getChildData(delegate, parent, name, attributes, symlinkTarget); if (childData != null) { int childId = makeChildRecord(parentId, name, childData, delegate); appendIdToParentList(parentId, childId); @@ -1224,14 +1225,16 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis return childId; } - private static Pair getChildData(@Nullable FileAttributes attributes, + private static Pair getChildData(@NotNull NewVirtualFileSystem fs, @NotNull VirtualFile parent, @NotNull String name, - @NotNull NewVirtualFileSystem fs) { - if (attributes == null) attributes = fs.getAttributes(new FakeVirtualFile(parent, name)); - if (attributes == null) return null; - String symlinkTarget = attributes.isSymLink() ? fs.resolveSymLink(new FakeVirtualFile(parent, name)) : null; - return pair(attributes, symlinkTarget); + @Nullable FileAttributes attributes, + @Nullable String symlinkTarget) { + if (attributes == null) { + attributes = fs.getAttributes(new FakeVirtualFile(parent, name)); + symlinkTarget = attributes != null && attributes.isSymLink() ? fs.resolveSymLink(new FakeVirtualFile(parent, name)) : null; + } + return attributes == null ? null : pair(attributes, symlinkTarget); } private static void appendIdToParentList(int parentId, int childId) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java index eacc25467eb3..b48fbef968d5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java @@ -107,7 +107,7 @@ public class RefreshWorker { } NewVirtualFile parent = file.getParent(); - if (parent != null && checkAndScheduleFileTypeChange(parent, file, attributes)) { + if (parent != null && checkAndScheduleFileTypeChange(fs, parent, file, attributes)) { // ignore everything else file.markClean(); continue; @@ -164,10 +164,16 @@ public class RefreshWorker { OpenTHashSet actualNames = fs.isCaseSensitive() ? null : new OpenTHashSet<>(strategy, upToDateNames); if (LOG.isTraceEnabled()) LOG.trace("current=" + Arrays.toString(currentNames) + " +" + newNames + " -" + deletedNames); - List> addedMap = ContainerUtil.newArrayListWithCapacity(newNames.size()); + List newKids = ContainerUtil.newArrayListWithCapacity(newNames.size()); for (String name : newNames) { checkCancelled(dir); - addedMap.add(pair(name, fs.getAttributes(new FakeVirtualFile(dir, name)))); + NewChildRecord record = childRecord(fs, dir, name); + if (record != null) { + newKids.add(record); + } + else { + if (LOG.isTraceEnabled()) LOG.trace("[+] fs=" + fs + " dir=" + dir + " name=" + name); + } } List> updatedMap = ContainerUtil.newArrayListWithCapacity(children.length); @@ -191,22 +197,15 @@ public class RefreshWorker { } } - for (Pair pair : addedMap) { - String name = pair.first; - FileAttributes childAttributes = pair.second; - if (childAttributes != null) { - myHelper.scheduleCreation(dir, name, appendPath(dir.getPath(), name), childAttributes); - } - else { - if (LOG.isTraceEnabled()) LOG.trace("[+] fs=" + fs + " dir=" + dir + " name=" + name); - } + for (NewChildRecord record : newKids) { + myHelper.scheduleCreation(dir, record.name, record.path, record.attributes, record.symlinkTarget); } for (Pair pair : updatedMap) { VirtualFile child = pair.first; FileAttributes childAttributes = pair.second; if (childAttributes != null) { - checkAndScheduleChildRefresh(dir, child, childAttributes); + checkAndScheduleChildRefresh(fs, dir, child, childAttributes); checkAndScheduleFileNameChange(actualNames, child); } else { @@ -255,11 +254,14 @@ public class RefreshWorker { existingMap.add(pair(child, fs.getAttributes(child))); } - List> wantedMap = ContainerUtil.newArrayListWithCapacity(wanted.size()); + List newKids = ContainerUtil.newArrayListWithCapacity(wanted.size()); for (String name : wanted) { if (name.isEmpty()) continue; checkCancelled(dir); - wantedMap.add(pair(name, fs.getAttributes(new FakeVirtualFile(dir, name)))); + NewChildRecord record = childRecord(fs, dir, name); + if (record != null) { + newKids.add(record); + } } // generating events unless a directory was changed in between @@ -273,7 +275,7 @@ public class RefreshWorker { VirtualFile child = pair.first; FileAttributes childAttributes = pair.second; if (childAttributes != null) { - checkAndScheduleChildRefresh(dir, child, childAttributes); + checkAndScheduleChildRefresh(fs, dir, child, childAttributes); checkAndScheduleFileNameChange(actualNames, child); } else { @@ -281,12 +283,8 @@ public class RefreshWorker { } } - for (Pair pair : wantedMap) { - String name = pair.first; - FileAttributes childAttributes = pair.second; - if (childAttributes != null) { - myHelper.scheduleCreation(dir, name, appendPath(dir.getPath(), name), childAttributes); - } + for (NewChildRecord record : newKids) { + myHelper.scheduleCreation(dir, record.name, record.path, record.attributes, record.symlinkTarget); } return true; @@ -297,6 +295,28 @@ public class RefreshWorker { } } + private static class NewChildRecord { + final String name; + final Path path; + final FileAttributes attributes; + final String symlinkTarget; + + NewChildRecord(String name, Path path, FileAttributes attributes, String symlinkTarget) { + this.name = name; + this.path = path; + this.attributes = attributes; + this.symlinkTarget = symlinkTarget; + } + } + + private static NewChildRecord childRecord(NewVirtualFileSystem fs, VirtualFile dir, String name) { + FakeVirtualFile file = new FakeVirtualFile(dir, name); + FileAttributes attributes = fs.getAttributes(file); + if (attributes == null) return null; + String symlinkTarget = attributes.isSymLink() ? fs.resolveSymLink(file) : null; + return new NewChildRecord(name, appendPath(dir.getPath(), name), attributes, symlinkTarget); + } + private void checkAndScheduleFileNameChange(@Nullable OpenTHashSet actualNames, @NotNull VirtualFile child) { if (actualNames != null) { String currentName = child.getName(); @@ -327,10 +347,11 @@ public class RefreshWorker { file.markDirty(); } - private void checkAndScheduleChildRefresh(@NotNull VirtualFile parent, + private void checkAndScheduleChildRefresh(NewVirtualFileSystem fs, + @NotNull VirtualFile parent, @NotNull VirtualFile child, @NotNull FileAttributes childAttributes) { - if (!checkAndScheduleFileTypeChange(parent, child, childAttributes)) { + if (!checkAndScheduleFileTypeChange(fs, parent, child, childAttributes)) { boolean upToDateIsDirectory = childAttributes.isDirectory(); if (myIsRecursive || !upToDateIsDirectory) { myRefreshQueue.addLast(pair((NewVirtualFile)child, childAttributes)); @@ -338,7 +359,8 @@ public class RefreshWorker { } } - private boolean checkAndScheduleFileTypeChange(@NotNull VirtualFile parent, + private boolean checkAndScheduleFileTypeChange(NewVirtualFileSystem fs, + @NotNull VirtualFile parent, @NotNull VirtualFile child, @NotNull FileAttributes childAttributes) { boolean currentIsDirectory = child.isDirectory(); @@ -350,7 +372,8 @@ public class RefreshWorker { if (currentIsDirectory != upToDateIsDirectory || currentIsSymlink != upToDateIsSymlink || currentIsSpecial != upToDateIsSpecial) { myHelper.scheduleDeletion(child); - myHelper.scheduleCreation(parent, child.getName(), appendPath(parent.getPath(), child.getName()), childAttributes); + String symlinkTarget = upToDateIsSymlink ? fs.resolveSymLink(child) : null; + myHelper.scheduleCreation(parent, child.getName(), appendPath(parent.getPath(), child.getName()), childAttributes, symlinkTarget); return true; } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VfsEventGenerationHelper.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VfsEventGenerationHelper.java index 4e8c8d6d130b..a09a11a6b9b4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VfsEventGenerationHelper.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VfsEventGenerationHelper.java @@ -46,11 +46,15 @@ class VfsEventGenerationHelper { myEvents.add(new VFileContentChangeEvent(null, file, file.getModificationStamp(), -1, oldTimestamp, newTimestamp, oldLength, newLength, true)); } - void scheduleCreation(@NotNull VirtualFile parent, @NotNull String childName, @NotNull Path path, @NotNull FileAttributes attributes) { + void scheduleCreation(@NotNull VirtualFile parent, + @NotNull String childName, + @NotNull Path path, + @NotNull FileAttributes attributes, + String symlinkTarget) { boolean isEmptyDir = attributes.isDirectory() && !LocalFileSystemBase.hasChildren(path); if (LOG.isTraceEnabled()) LOG.trace("create parent=" + parent + " name=" + childName + " attr=" + attributes); - myEvents.add(new VFileCreateEvent(null, parent, childName, attributes.isDirectory(), attributes, true, isEmptyDir)); + myEvents.add(new VFileCreateEvent(null, parent, childName, attributes.isDirectory(), attributes, symlinkTarget, true, isEmptyDir)); } void scheduleDeletion(@NotNull VirtualFile file) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java index f5ebb5b28d6d..0e36487a14ea 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java @@ -103,14 +103,23 @@ interface GlobalMenuLib extends Library { public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { private static final SimpleDateFormat ourDtf = new SimpleDateFormat("hhmmss.SSS"); // for debug only - private static final boolean TRACE_SYSOUT = System.getProperty("linux.native.menu.debug.trace.sysout", "false").equals("true"); - private static final boolean TRACE_DISABLED = System.getProperty("linux.native.menu.debug.trace.disabled", "true").equals("true"); - private static final boolean TRACE_SYNC_STATS = System.getProperty("linux.native.menu.debug.trace.sync-stats", "false").equals("true"); - private static final boolean TRACE_EVENTS = System.getProperty("linux.native.menu.debug.trace.events", "false").equals("true"); - private static final boolean TRACE_EVENT_FILTER = System.getProperty("linux.native.menu.debug.trace.event-filter", "false").equals("true"); - private static final boolean TRACE_CLEARING = System.getProperty("linux.native.menu.debug.trace.clearing", "false").equals("true"); - private static final boolean TRACE_HIERARCHY_MISMATCHES = System.getProperty("linux.native.menu.debug.trace.hierarchy.mismatches","false").equals("true"); - private static final boolean SHOW_SWING_MENU = System.getProperty("linux.native.menu.debug.show.frame.menu", "false").equals("true"); + private static final boolean TRACE_SYSOUT = Boolean.getBoolean("linux.native.menu.debug.trace.sysout"); + private static final boolean TRACE_ENABLED = Boolean.getBoolean("linux.native.menu.debug.trace.enabled"); + private static final boolean TRACE_SYNC_STATS = Boolean.getBoolean("linux.native.menu.debug.trace.sync-stats"); + private static final boolean TRACE_EVENTS = Boolean.getBoolean("linux.native.menu.debug.trace.events"); + private static final boolean TRACE_EVENT_FILTER = Boolean.getBoolean("linux.native.menu.debug.trace.event-filter"); + private static final boolean TRACE_SKIPPED_EVENT = Boolean.getBoolean("linux.native.menu.debug.trace.skipped.event"); + private static final boolean TRACE_CLEARING = Boolean.getBoolean("linux.native.menu.debug.trace.clearing"); + private static final boolean TRACE_HIERARCHY_MISMATCHES = Boolean.getBoolean("linux.native.menu.debug.trace.hierarchy.mismatches"); + private static final boolean SHOW_SWING_MENU = Boolean.getBoolean("linux.native.menu.debug.show.frame.menu"); + + private static final boolean KDE_DISABLE_ROOT_MNEMONIC_PROCESSING = Boolean.getBoolean("linux.native.menu.kde.disable.root.mnemonic"); + + private static final boolean SKIP_OPEN_MENU_COMMAND = Boolean.getBoolean("linux.native.menu.skip.open"); + private static final boolean DONT_FILL_ROOTS = SystemInfo.isKDE || Boolean.getBoolean("linux.native.dont.fill.roots"); + private static final boolean DONT_FILL_SUBMENU = Boolean.getBoolean("linux.native.menu.dont.fill.submenu"); + private static final boolean DONT_CLOSE_POPUPS = Boolean.getBoolean("linux.native.menu.dont.close.popups"); + private static final boolean DISABLE_EVENTS_FILTERING = Boolean.getBoolean("linux.native.menu.disable.events.filtering"); private static final Logger LOG = Logger.getInstance(GlobalMenuLinux.class); private static final GlobalMenuLib ourLib; @@ -128,6 +137,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { private boolean myIsRootsUpdated = false; private boolean myIsEnabled = true; private boolean myIsDisposed = false; + private boolean myIsFirstFilling = true; // don't filter first packet of events (it causes slow reaction of KDE applet) private final GlobalMenuLib.JRunnable myOnWindowReleased; private final EventFilter myEventFilter = new EventFilter(); @@ -212,7 +222,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { ourInstances.remove(myXid); }; - if (SystemInfo.isKDE) { + if (SystemInfo.isKDE && !KDE_DISABLE_ROOT_MNEMONIC_PROCESSING) { // root menu items doesn't catch mnemonic shortcuts (in KDE), so process them inside IDE IdeEventQueue.getInstance().addDispatcher(e -> { if (!(e instanceof KeyEvent)) @@ -298,15 +308,26 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { ApplicationManager.getApplication().assertIsDispatchThread(); + int[] stats = new int[]{0, 0, 0}; final int size = roots == null ? 0 : roots.size(); final List newRoots = new ArrayList<>(size); + if (roots != null) { for (ActionMenu am: roots) { final int uid = System.identityHashCode(am); - final MenuItemInternal mi = new MenuItemInternal(newRoots.size(), uid, GlobalMenuLib.ITEM_SUBMENU, am.getAnAction()); + final MenuItemInternal mi = new MenuItemInternal(null, newRoots.size(), uid, GlobalMenuLib.ITEM_SUBMENU, am.getAnAction()); mi.jitem = am; mi.setLabelFromSwingPeer(am); newRoots.add(mi); + + if (!DONT_FILL_ROOTS) { + final long startMs = System.currentTimeMillis(); + am.removeAll(); + am.fillMenu(); + _syncChildren(mi, am, 1, stats); // NOTE: fill root menus to avoid empty submenu showing + final long elapsedMs = System.currentTimeMillis() - startMs; + if (TRACE_SYNC_STATS) _trace("filled root menu '%s', spent (in EDT) %d ms, stats: %s", String.valueOf(mi.txt), elapsedMs, _stats2str(stats)); + } } } @@ -430,20 +451,20 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { } } - private static MenuItemInternal _createInternalFromSwing(Component each) { + private static MenuItemInternal _createInternalFromSwing(MenuItemInternal parent, Component each) { if (each == null) return null; MenuItemInternal result = null; if (each instanceof ActionMenuItem) { final ActionMenuItem ami = (ActionMenuItem)each; - result = new MenuItemInternal(-1, System.identityHashCode(ami), ami.isToggleable() ? GlobalMenuLib.ITEM_CHECK : GlobalMenuLib.ITEM_SIMPLE, ami.getAnAction()); + result = new MenuItemInternal(parent, -1, System.identityHashCode(ami), ami.isToggleable() ? GlobalMenuLib.ITEM_CHECK : GlobalMenuLib.ITEM_SIMPLE, ami.getAnAction()); result.jitem = ami; } else if (each instanceof ActionMenu) { final ActionMenu am2 = (ActionMenu)each; - result = new MenuItemInternal(-1, System.identityHashCode(am2), GlobalMenuLib.ITEM_SUBMENU, am2.getAnAction()); + result = new MenuItemInternal(parent, -1, System.identityHashCode(am2), GlobalMenuLib.ITEM_SUBMENU, am2.getAnAction()); result.jitem = am2; } else if (each instanceof JSeparator) { - result = new MenuItemInternal(-1, System.identityHashCode(each), GlobalMenuLib.ITEM_SIMPLE, null); + result = new MenuItemInternal(parent, -1, System.identityHashCode(each), GlobalMenuLib.ITEM_SIMPLE, null); } else if (each instanceof StubItem) { // System.out.println("skip StubItem"); } else { @@ -476,7 +497,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { for (Component each : am.getPopupMenu().getComponents()) { MenuItemInternal cmi = mi.findCorrespondingChild(each); if (cmi == null) { - cmi = _createInternalFromSwing(each); + cmi = _createInternalFromSwing(mi, each); if (cmi != null) { cmi.position = itemPos++; mi.children.add(cmi); @@ -493,8 +514,12 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { } } if (cmi != null) { - if (deepness > 1 && (each instanceof ActionMenu)) - _syncChildren(cmi, (ActionMenu)each, deepness - 1, stats); + if (deepness > 1 && (each instanceof ActionMenu)) { + final ActionMenu jmiEach = (ActionMenu)each; + jmiEach.removeAll(); + jmiEach.fillMenu(); + _syncChildren(cmi, jmiEach, deepness - 1, stats); + } } } } @@ -542,8 +567,15 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { } } + private static boolean _isFillEvent(int eventType) { + return eventType == GlobalMenuLib.SIGNAL_ABOUT_TO_SHOW || (!SKIP_OPEN_MENU_COMMAND && eventType == GlobalMenuLib.EVENT_OPENED); + } + @Override public void handleEvent(int uid, int eventType) { + _handleEvent(uid, eventType, true); + } + private void _handleEvent(int uid, int eventType, boolean doFiltering) { // glib main-loop thread final MenuItemInternal mi = _findMenuItem(uid); if (mi == null) { @@ -561,16 +593,27 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { if (TRACE_EVENTS) _trace("received event '%s' from item %s", _evtype2str(eventType), mi); - if (eventType == GlobalMenuLib.SIGNAL_ABOUT_TO_SHOW || eventType == GlobalMenuLib.EVENT_CLOSED) { - final boolean check = myEventFilter.check(uid, eventType, mi); - if (!check) - return; + if (!DISABLE_EVENTS_FILTERING && !myIsFirstFilling && doFiltering && !myEventFilter.check(uid, eventType, mi)) + return; - if (eventType == GlobalMenuLib.SIGNAL_ABOUT_TO_SHOW) { + if (myIsFirstFilling) { + final Timer timer = new Timer(5000, e -> myIsFirstFilling = false); + timer.setRepeats(false); + timer.start(); + } + + if (_isFillEvent(eventType)) { // glib main-loop thread - final long startMs = System.currentTimeMillis(); - int[] stats = new int[]{0, 0, 0}; + if (!DONT_CLOSE_POPUPS) + ApplicationManager.getApplication().invokeLater(() -> IdeEventQueue.getInstance().getPopupManager().closeAllPopups()); + mi.cancelClearSwing(); + // simple check to avoid double (or frequent) filling + final long timeMs = System.currentTimeMillis(); + int[] stats = new int[]{0, 0, 0}; + if (timeMs - mi.lastFilledMs < 1500 && mi.lastClearedMs < mi.lastFilledMs) { + if (TRACE_SKIPPED_EVENT) _trace("skipped fill-event for item '%s', use cached (too frequent fill-events)", String.valueOf(mi.txt)); + } else { ApplicationManager.getApplication().invokeAndWait(()-> { // ETD-start final JMenuItem jmi = mi.jitem; @@ -583,23 +626,25 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { return; } + mi.lastFilledMs = timeMs; + final ActionMenu am = (ActionMenu)jmi; am.removeAll(); am.fillMenu(); - _syncChildren(mi, am, 1, stats); + _syncChildren(mi, am, DONT_FILL_SUBMENU ? 1 : 2, stats); // NOTE: fill next submenus level to avoid empty submenu showing (intermittent behaviour of menu-applet) }); // glib main-loop thread - final long elapsedMs = System.currentTimeMillis() - startMs; - if (TRACE_SYNC_STATS) _trace("opened %s '%s', spent (in EDT) %d ms, stats: %s", (mi.isRoot() ? "root menu" : "submenu"), String.valueOf(mi.txt), elapsedMs, _stats2str(stats)); + final long elapsedMs = System.currentTimeMillis() - timeMs; + if (TRACE_SYNC_STATS) _trace("filled menu %s '%s', spent (in EDT) %d ms, stats: %s", (mi.isRoot() ? "root menu" : "submenu"), String.valueOf(mi.txt), elapsedMs, _stats2str(stats)); _processChildren(mi); - } else { - // glib main-loop thread - // process GlobalMenuLib.EVENT_CLOSED - mi.scheduleClearSwing(); } + } + if (eventType == GlobalMenuLib.EVENT_CLOSED) { + // glib main-loop thread + mi.scheduleClearSwing(); return; } @@ -682,6 +727,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { final int type; final AnAction action; + final MenuItemInternal parent; final List children = new ArrayList<>(); String txt; @@ -698,11 +744,13 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { Pointer nativePeer; int position = -1; - long lastClosedMs = 0; + long lastFilledMs = 0; + long lastClearedMs = 0; Timer timerClearSwing; - MenuItemInternal(int rootPos, int uid, int type, AnAction action) { + MenuItemInternal(MenuItemInternal parent, int rootPos, int uid, int type, AnAction action) { + this.parent = parent; this.rootPos = rootPos; this.uid = uid; this.type = type; @@ -779,7 +827,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { final int x11keycode = X11KeyCodes.jkeycode2X11code(jkeycode, 0); if (x11keycode != 0) ourLib.setItemShortcut(nativePeer, jmodifiers, x11keycode); - else if (!TRACE_DISABLED) + else if (TRACE_ENABLED) _trace("unknown x11 keycode for jcode=" + jkeycode); } } @@ -865,15 +913,28 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { void scheduleClearSwing() { // exec at glib main-loop thread - if (timerClearSwing != null) - timerClearSwing.stop(); + if (timerClearSwing != null) { + timerClearSwing.restart(); + if (TRACE_CLEARING) _trace("\t reset clear timer of item '%s'", toStringShort()); + return; + } - timerClearSwing = new Timer(300, (e)->_clearSwing()); + timerClearSwing = new Timer(2000, (e)->_clearSwing()); timerClearSwing.setRepeats(false); timerClearSwing.start(); if (TRACE_CLEARING) _trace("\t scheduled (300 ms later) to clear '%s'", toStringShort()); } + void cancelClearSwing() { + // exec at glib main-loop thread + if (timerClearSwing != null) { + timerClearSwing.stop(); + timerClearSwing = null; + } + for (MenuItemInternal p = parent; p != null; p = p.parent) + p.cancelClearSwing(); + } + private void _clearSwing() { // exec at ETD if (timerClearSwing == null) @@ -891,59 +952,157 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { final ActionMenu am = (ActionMenu)jitem; am.clearItems(); clearChildrenSwingRefs(); + _onSwingCleared(System.currentTimeMillis()); if (TRACE_CLEARING) _trace("\t cleared '%s'", toStringShort()); } + + private void _onSwingCleared(long timeMs) { + lastClearedMs = timeMs; + if (timerClearSwing != null) { + timerClearSwing.stop(); + timerClearSwing = null; + } + + for (MenuItemInternal kid: children) + kid._onSwingCleared(timeMs); + } + } + + private static class QueuedEvent { + final int uid; + final int eventType; + final int rootId; + final long timeMs; + + private QueuedEvent(int uid, int eventType, int rootId, long timeMs) { + this.uid = uid; + this.eventType = eventType; + this.rootId = rootId; + this.timeMs = timeMs; + } + + static QueuedEvent of(int uid, int eventType, int rootId, long timeMs) { + return new QueuedEvent(uid, eventType, rootId, timeMs); + } } private class EventFilter { + final private ArrayList myQueued = new ArrayList<>(); private Timer myTimer; - private long myLastFirstRootEventMs = 0; + private long myClosedMs = 0; + @SuppressWarnings("unused") private GlobalMenuLib.JRunnable myGlibLoopRunnable; // holds runnable object - boolean check(int uid, int eventType, @NotNull MenuItemInternal mi) { - final long timeMs = System.currentTimeMillis(); - if (eventType == GlobalMenuLib.EVENT_CLOSED) { - mi.lastClosedMs = timeMs; - } else { - if (mi.rootPos == 0) { - if (myTimer == null) { - myLastFirstRootEventMs = timeMs; - // start timer to call handleEvent(uid, eventType) after several ms - myTimer = new Timer(50, (e) -> { - if (myTimer == null) { - if (TRACE_EVENT_FILTER) _trace("EventFilter: skip delayed 'about-to-show' processing of first-root because timer was reset (i.e. myTimer == null)"); - return; - } - ourLib.execOnMainLoop(myGlibLoopRunnable = () -> handleEvent(uid, eventType)); - }); - myTimer.setRepeats(false); - myTimer.start(); - if (TRACE_EVENT_FILTER) _trace("EventFilter: start timer to process 'about-to-show' of first-root later"); - return false; + private boolean _isClosed() { return myClosedMs > 0; } + + private void _stopTimer() { + // exec at glib-main-thread + if (myTimer != null) + myTimer.stop(); + myTimer = null; + } + + private void _processQueue() { + // exec at glib-main-thread + for (QueuedEvent q: myQueued) + _handleEvent(q.uid, q.eventType, false); + myQueued.clear(); + } + + private void _startTimer() { + // exec at glib-main-thread + _stopTimer(); + + final Timer timer = new Timer(50, null); + timer.addActionListener((e) -> { + if (TRACE_EVENT_FILTER) _trace("EventFilter: start execution of timer callback"); // exec at EDT + if (myTimer != timer) {// check that timer wasn't reset + if (TRACE_EVENT_FILTER) _trace("EventFilter: skip timer-processing because timer was reset (i.e. myTimer == null)"); + return; + } + + ourLib.execOnMainLoop(myGlibLoopRunnable = () -> { + // remove continuous series of sequential root events + // because some of implementations (of menu applet) regularly send packets of root events ('about-to-show' or/and 'open') + final int lastRootId = myRoots.size() - 1; + int from = 0; + while (from < myQueued.size()) { + final int size = myQueued.size(); + + // 1. find event from second root + while (from < size && myQueued.get(from).rootId != 1) ++from; + if (from == size) break; + + // 2. rewind to first root + int first = from - 1; + if (first < 0 || myQueued.get(first).rootId != 0) { + // no events from first root, rewind forward + while (from < size && myQueued.get(from).rootId == 1) ++from; + continue; + } + while (first >= 1 && myQueued.get(first - 1).rootId == 0 && from - first <= 1) --first; + + // 3. find last root + int to = from + 1; + while (to < size && myQueued.get(to).rootId != lastRootId) ++to; + if (to == size) break; + while (to < size && myQueued.get(to).rootId == lastRootId) ++to; + + // 4. remove fake segment + if (TRACE_EVENT_FILTER) _trace("EventFilter: remove segment [%d, %d) from queue of size=%d", first, to, myQueued.size()); + myQueued.subList(first, to).clear(); + from = first + 1; } + if (!myQueued.isEmpty()) { + if (TRACE_ENABLED) _trace("EventFilter: process queued events, size=%d", myQueued.size()); + _processQueue(); + } else if (TRACE_ENABLED) _trace("EventFilter: queue is empty"); + myTimer = null; - } else if (mi.rootPos > 0) { - if ((timeMs - myLastFirstRootEventMs) < 50) { - if (TRACE_EVENT_FILTER) _trace("EventFilter: skip fake 'about-to-show' of root[%d]%s", mi.rootPos, myTimer != null ? " (reset timer)" : ""); - if (myTimer != null) { - myTimer.stop(); - myTimer = null; - } - return false; - } - if (TRACE_EVENT_FILTER) _trace("EventFilter: process real 'about-to-show' on root[%d]", mi.rootPos); + myClosedMs = 0; // open filter + if (TRACE_EVENT_FILTER) _trace("EventFilter: filter is opened"); + }); + }); + + myTimer = timer; + myTimer.setRepeats(false); + myTimer.start(); + if (TRACE_EVENT_FILTER) _trace("EventFilter: start timer"); + } + + boolean check(int uid, int eventType, @NotNull MenuItemInternal mi) { + // exec at glib-main-thread + final boolean isFillEvent = _isFillEvent(eventType); + final long timeMs = System.currentTimeMillis(); + + if (_isClosed()) { + if (timeMs - myClosedMs > 2000) { + // simple protection (open filter by timeout) + if (TRACE_ENABLED) _trace("EventFilter WARNING: close filter by timeout protection"); + _processQueue(); + _stopTimer(); + myClosedMs = 0; } else { - if (TRACE_EVENT_FILTER) _trace("EventFilter: process real 'about-to-show' on non-root item '%s'%s", mi.txt, myTimer != null ? " (reset timer)" : ""); - if (myTimer != null) { - myTimer.stop(); - myTimer = null; - } + // filter is closed + myQueued.add(QueuedEvent.of(uid, eventType, mi.rootPos, timeMs)); + if (myTimer != null) + myTimer.restart(); + return false; } } - return true; + // filter is opened + if (mi.rootPos != 0) + return true; + + // filter is opened and first root appeared + if (TRACE_EVENT_FILTER) _trace("EventFilter: close filter"); + myQueued.add(QueuedEvent.of(uid, eventType, mi.rootPos, timeMs)); + myClosedMs = timeMs; + _startTimer(); + return false; } } @@ -1023,14 +1182,14 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { } private static void _trace(String fmt, Object... args) { - if (TRACE_DISABLED) + if (!TRACE_ENABLED) return; final String msg = String.format(fmt, args); _trace(msg); } private static void _trace(String msg) { - if (TRACE_DISABLED) + if (!TRACE_ENABLED) return; if (TRACE_SYSOUT) //noinspection UseOfSystemOutOrSystemErr diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java index cc551e16e0d5..935895791078 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java @@ -34,6 +34,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.AbstractPainter; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.StatusBar; import com.intellij.ui.EditorTextField; @@ -57,6 +58,7 @@ import java.awt.geom.*; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ImageObserver; +import java.awt.image.VolatileImage; import java.net.URL; import java.util.Set; @@ -69,6 +71,8 @@ public class IdeBackgroundUtil { public static final String FRAME_PROP = "idea.background.frame"; public static final String TARGET_PROP = "idea.background.target"; + public static final Key NO_BACKGROUND = Key.create("SUPPRESS_BACKGROUND"); + public enum Fill { PLAIN, SCALE, TILE } @@ -374,12 +378,14 @@ public class IdeBackgroundUtil { void runAllPainters(int x, int y, int width, int height, @Nullable Shape sourceShape, @Nullable Object reason) { if (width <= 1 || height <= 1) return; - // skip painters for transparent 'reasons' - if (reason instanceof Color && ((Color)reason).getAlpha() < 255) return; - if (reason instanceof Image) { - if (!(reason instanceof BufferedImage)) return; - if (((BufferedImage)reason).getColorModel().hasAlpha()) return; - } + boolean hasAlpha = + reason instanceof Color ? ((Color)reason).getAlpha() < 255 : + reason instanceof BufferedImage ? ((BufferedImage)reason).getColorModel().hasAlpha() : + reason instanceof VolatileImage ? ((VolatileImage)reason).getTransparency() != Transparency.OPAQUE : + true; + // skip painters when alpha is already present + if (hasAlpha) return; + Shape prevClip = getClip(); Shape tmpClip = calcTempClip(prevClip, sourceShape != null ? sourceShape : new Rectangle(x, y, width, height)); if (tmpClip == null) return; @@ -400,6 +406,7 @@ public class IdeBackgroundUtil { private static class MyTransform implements PairFunction { @Override public Graphics2D fun(JComponent c, Graphics2D g) { + if (Boolean.TRUE.equals(UIUtil.getClientProperty(c, NO_BACKGROUND))) return g; String type = getComponentType(c); if (type == null) return g; if ("frame".equals(type)) return withFrameBackground(g, c); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java index bc1348e4f3cd..ab371edfd51c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java @@ -421,7 +421,12 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr @NotNull private DefaultActionGroup createResizeActionGroup() { - DefaultActionGroup resize = new DefaultActionGroup(ActionsBundle.groupText("ResizeToolWindowGroup"), true); + DefaultActionGroup resize = new DefaultActionGroup(ActionsBundle.groupText("ResizeToolWindowGroup"), true) { + @Override + public boolean isDumbAware() { + return true; + } + }; resize.add(new ResizeToolWindowAction.Left(myToolWindow, this)); resize.add(new ResizeToolWindowAction.Right(myToolWindow, this)); resize.add(new ResizeToolWindowAction.Up(myToolWindow, this)); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index a98e1393c83b..c23eef2b9264 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -195,7 +195,7 @@ public class ToolWindowManagerImpl extends ToolWindowManagerEx implements Persis .handleFocusLostOnPinned(toolWindowId -> { List commands = new ArrayList<>(); deactivateToolWindowImpl(getRegisteredInfoOrLogError(toolWindowId), true, commands); - myCommandProcessor.execute(commands, myProject.getDisposed()); + execute(commands, true); // notify clients that toolwindow is deactivated }) .handleWindowed(toolWindowId -> {}) .bind(myProject); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/MoreIcon.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/MoreIcon.java index 562163f38f2c..59458d78d2a1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/MoreIcon.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/MoreIcon.java @@ -29,7 +29,7 @@ public abstract class MoreIcon { private final ActiveIcon myRight = new ActiveIcon(AllIcons.General.ArrowRight, IconLoader.getDisabledIcon(AllIcons.General.ArrowRight)); - protected final int myGap = 2; + protected static final int myGap = 2; protected boolean myLeftPainted; protected boolean myRightPainted; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/CardActionsPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/CardActionsPanel.java index edfc38ab6a18..dfa018035d3a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/CardActionsPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/CardActionsPanel.java @@ -40,7 +40,7 @@ import java.util.ArrayList; import java.util.List; public class CardActionsPanel extends JPanel { - private final boolean USE_ICONS = true; + private static final boolean USE_ICONS = true; private final JBCardLayout myLayout = new JBCardLayout(); private final JPanel myContent = new JPanel(myLayout); private int nCards = 0; diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsBuilder.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsBuilder.java index 0e8ebba6f785..5a71ca1f2300 100644 --- a/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsBuilder.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsBuilder.java @@ -23,9 +23,9 @@ import org.jetbrains.annotations.Nullable; */ public class RemoteSdkCredentialsBuilder { private String myInterpreterPath = null; - private final String myHelpersPath = null; + private static final String myHelpersPath = null; private RemoteCredentials myRemoteCredentials = null; - private final String myHelpersDefaultDirName = ".idea_helpers"; + private static final String myHelpersDefaultDirName = ".idea_helpers"; public RemoteSdkCredentials build() { diff --git a/platform/platform-impl/src/com/intellij/ui/EditorNotificationsImpl.java b/platform/platform-impl/src/com/intellij/ui/EditorNotificationsImpl.java index b436c5678340..f36ff9ee04e6 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorNotificationsImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorNotificationsImpl.java @@ -2,18 +2,14 @@ package com.intellij.ui; import com.intellij.ProjectTopics; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.application.impl.NonBlockingReadActionImpl; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.FileEditorManagerListener; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.fileEditor.impl.text.AsyncEditorLoader; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.util.ProgressIndicatorBase; -import com.intellij.openapi.progress.util.ProgressIndicatorUtils; -import com.intellij.openapi.progress.util.ReadTask; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootEvent; @@ -25,7 +21,6 @@ import com.intellij.psi.PsiFile; import com.intellij.refactoring.listeners.RefactoringElementAdapter; import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.refactoring.listeners.RefactoringElementListenerProvider; -import com.intellij.reference.SoftReference; import com.intellij.util.SmartList; import com.intellij.util.concurrency.SequentialTaskExecutor; import com.intellij.util.containers.ContainerUtil; @@ -35,9 +30,10 @@ import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; +import org.jetbrains.concurrency.CancellablePromise; import javax.swing.*; -import java.lang.ref.WeakReference; import java.util.List; import java.util.concurrent.ExecutorService; @@ -45,7 +41,7 @@ import java.util.concurrent.ExecutorService; * @author peter */ public class EditorNotificationsImpl extends EditorNotifications { - private static final Key> CURRENT_UPDATES = Key.create("CURRENT_UPDATES"); + private final Key> CURRENT_UPDATE = Key.create("EditorNotifications update"); // non-static, per-project private static final ExecutorService ourExecutor = SequentialTaskExecutor.createSequentialApplicationPoolExecutor( "EditorNotificationsImpl Pool"); private final MergingUpdateQueue myUpdateMerger; @@ -83,89 +79,42 @@ public class EditorNotificationsImpl extends EditorNotifications { @Override public void updateNotifications(@NotNull final VirtualFile file) { UIUtil.invokeLaterIfNeeded(() -> { - ProgressIndicator indicator = getCurrentProgress(file); - if (indicator != null) { - indicator.cancel(); - } - file.putUserData(CURRENT_UPDATES, null); - if (myProject.isDisposed() || !file.isValid()) { return; } - indicator = new ProgressIndicatorBase(); - final ReadTask task = createTask(indicator, file); - if (task == null) return; + CancellablePromise prev = file.getUserData(CURRENT_UPDATE); + if (prev != null) { + prev.cancel(); + } - file.putUserData(CURRENT_UPDATES, new WeakReference<>(indicator)); - if (ApplicationManager.getApplication().isUnitTestMode()) { - ReadTask.Continuation continuation = task.performInReadAction(indicator); - if (continuation != null) { - continuation.getAction().run(); - } - } - else { - ProgressIndicatorUtils.scheduleWithWriteActionPriority(indicator, ourExecutor, task); - } + CancellablePromise> promise = ReadAction. + nonBlocking(() -> calcNotificationUpdates(file)). + expireWhen(() -> !file.isValid() || myProject.isDisposed()). + finishOnUiThread(ModalityState.any(), updates -> { + for (Runnable update : updates) { + update.run(); + } + }). + submit(ourExecutor); + file.putUserData(CURRENT_UPDATE, promise); + promise.onProcessed(__ -> file.putUserData(CURRENT_UPDATE, null)); }); } - @Nullable - private ReadTask createTask(@NotNull final ProgressIndicator indicator, @NotNull final VirtualFile file) { + @NotNull + private List calcNotificationUpdates(@NotNull VirtualFile file) { List editors = ContainerUtil.filter(FileEditorManager.getInstance(myProject).getAllEditors(file), editor -> !(editor instanceof TextEditor) || AsyncEditorLoader.isEditorLoaded(((TextEditor)editor).getEditor())); - if (editors.isEmpty()) return null; - - return new ReadTask() { - private boolean isOutdated() { - if (myProject.isDisposed() || !file.isValid() || indicator != getCurrentProgress(file)) { - return true; - } - - for (FileEditor editor : editors) { - if (!editor.isValid()) { - return true; - } - } - - return false; + List providers = DumbService.getDumbAwareExtensions(myProject, EXTENSION_POINT_NAME); + List updates = new SmartList<>(); + for (FileEditor editor : editors) { + for (Provider provider : providers) { + JComponent component = provider.createNotificationPanel(file, editor); + updates.add(() -> updateNotification(editor, provider.getKey(), component)); } - - @Nullable - @Override - public Continuation performInReadAction(@NotNull ProgressIndicator indicator) throws ProcessCanceledException { - if (isOutdated()) return null; - - final List providers = DumbService.getDumbAwareExtensions(myProject, EXTENSION_POINT_NAME); - final List updates = new SmartList<>(); - for (final FileEditor editor : editors) { - for (final Provider provider : providers) { - final JComponent component = provider.createNotificationPanel(file, editor); - updates.add(() -> updateNotification(editor, provider.getKey(), component)); - } - } - - return new Continuation(() -> { - if (!isOutdated()) { - file.putUserData(CURRENT_UPDATES, null); - for (Runnable update : updates) { - update.run(); - } - } - }, ModalityState.any()); - } - - @Override - public void onCanceled(@NotNull ProgressIndicator ignored) { - if (getCurrentProgress(file) == indicator) { - updateNotifications(file); - } - } - }; - } - - private static ProgressIndicator getCurrentProgress(VirtualFile file) { - return SoftReference.dereference(file.getUserData(CURRENT_UPDATES)); + } + return updates; } private void updateNotification(@NotNull FileEditor editor, @NotNull Key key, @Nullable JComponent component) { @@ -220,4 +169,10 @@ public class EditorNotificationsImpl extends EditorNotifications { return null; } } + + @TestOnly + public static void completeAsyncTasks() { + NonBlockingReadActionImpl.completeAsyncTasks(); + } + } diff --git a/platform/platform-impl/src/com/intellij/ui/TableCellEditorWithButton.java b/platform/platform-impl/src/com/intellij/ui/TableCellEditorWithButton.java index 359776ff12e1..b08060fad55c 100644 --- a/platform/platform-impl/src/com/intellij/ui/TableCellEditorWithButton.java +++ b/platform/platform-impl/src/com/intellij/ui/TableCellEditorWithButton.java @@ -15,7 +15,7 @@ public class TableCellEditorWithButton extends AbstractCellEditor implements Tab protected final MyComponent myComponent; protected final EditorDelegate delegate; - protected final int myClickCountToStart = 1; + protected static final int myClickCountToStart = 1; public TableCellEditorWithButton() { myComponent = new MyComponent(); diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 7f61a7d8eeb4..010f987717f2 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -519,8 +519,10 @@ action.GotoAction.text=_Find Action... action.GotoAction.description=Quickly navigate to action by name action.GotoLine.text=_Line/Column... action.GotoLine.description=Navigate to a line (and/or column) in editor by its number -action.GotoDeclaration.text=_Declaration -action.GotoDeclaration.description=Navigate to the declaration of the symbol at caret +action.GotoDeclaration.text=Declaration or Usages +action.GotoDeclaration.description=Navigate to the declaration of the symbol at caret or show its usages +action.GotoDeclarationOnly.text=_Declaration +action.GotoDeclarationOnly.description=Navigate to the declaration of the symbol at caret action.GotoImplementation.text=I_mplementation(s) action.GotoImplementation.description=Navigate to the implementation(s) of the selected class or method action.GotoNextElementUnderCaretUsage.text=Go to next highlighted element usage diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index 45391486b753..8de86b917e7e 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -496,9 +496,9 @@ checkbox.do.not.indent.top.level.class.members=Do not indent top level class mem checkbox.use.relative.indents=Use indents relative to expression start tooltip.indent.must.be.multiple.of.tab.size.for.smart.tabs.to.operate=Indent must be multiple of tab size for smart tabs to operate combobox.crlf.system.dependent=System-Dependent -combobox.crlf.unix=Unix and OS X (\\n) +combobox.crlf.unix=Unix and macOS (\\n) combobox.crlf.windows=Windows (\\r\\n) -combobox.crlf.mac=Classic Mac (\\r) +combobox.crlf.mac=Classic macOS (\\r) group.tabs.and.indents=Tabs and Indents checkbox.indent.use.same.settings.for.all.file.types=Use default indent options (General) tab.indent.other=Other diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index 8127a4b22da8..8d242127784f 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -196,7 +196,8 @@ inspection.field.can.be.local.problem.descriptor=Field can be converted to a loc inspection.parameter.can.be.local.display.name=Parameter can be local inspection.parameter.can.be.local.problem.descriptor=Parameter can be converted to a local variable inspection.convert.to.local.quickfix=Convert to local -inspection.field.can.be.local.quickfix.multiple.methods=Convert field to local variables in {0} methods +inspection.field.can.be.local.quickfix.initializer=Convert field to local variable in initializer section +inspection.field.can.be.local.quickfix.constructor=Convert field to local variable in constructor inspection.field.can.be.local.quickfix.one.method=Convert field to local variable in method ''{0}'' inspection.unused.return.value.display.name=Method can be void @@ -1051,20 +1052,13 @@ inspection.switch.expression.backward.expression.migration.inspection.name='swit inspection.switch.expression.backward.statement.migration.inspection.name='switch' statement can be replaced with old style 'switch' statement inspection.replace.with.old.style.switch.statement.fix.name=Replace with old style 'switch' statement -inspection.duplicate.branches.in.switch.display.name=Duplicate branches in 'switch' statement -inspection.duplicate.branches.in.switch.statement.message=Duplicate branch in 'switch' statement -inspection.duplicate.branches.in.switch.expression.message=Duplicate branch in 'switch' expression -inspection.duplicate.branches.in.switch.result.message=Duplicate result expression in 'switch' expression -inspection.duplicate.branches.in.switch.statement.default.message=Branch in 'switch' statement is a duplicate of the default branch -inspection.duplicate.branches.in.switch.expression.default.message=Branch in 'switch' expression is a duplicate of the default branch -inspection.duplicate.branches.in.switch.default.result.message=Result expression in 'switch' expression is a duplicate of the default result -inspection.duplicate.branches.in.switch.fix.family.name=Merge duplicate branches of 'switch' statement -inspection.duplicate.branches.in.switch.expression.fix.family.name=Merge duplicate results of 'switch' expression -inspection.duplicate.branches.in.switch.fix.name=Merge with ''{0}'' -inspection.duplicate.branches.in.switch.redundant.fix.family.name=Delete redundant branches of 'switch' statement -inspection.duplicate.branches.in.switch.redundant.expression.fix.family.name=Delete redundant branches of 'switch' expression -inspection.duplicate.branches.in.switch.redundant.fix.name=Delete redundant 'switch' branch -inspection.duplicate.branches.in.switch.redundant.expression.fix.name=Delete redundant 'switch' result expression +inspection.duplicate.branches.in.switch.display.name=Duplicate branches in 'switch' +inspection.duplicate.branches.in.switch.message=Duplicate branch in 'switch' +inspection.duplicate.branches.in.switch.default.message=Branch in 'switch' is a duplicate of the default branch +inspection.duplicate.branches.in.switch.merge.fix.family.name=Merge duplicate branches in 'switch' +inspection.duplicate.branches.in.switch.merge.fix.name=Merge with ''{0}'' +inspection.duplicate.branches.in.switch.delete.fix.family.name=Delete redundant 'switch' branches +inspection.duplicate.branches.in.switch.delete.fix.name=Delete redundant 'switch' branch inspection.duplicate.branches.in.switch.merge.with.default.fix.name=Merge with the default 'switch' branch inspection.switch.labeled.rule.can.be.code.block.display.name=Labeled switch rule can have code block diff --git a/platform/platform-resources-en/src/messages/VcsBundle.properties b/platform/platform-resources-en/src/messages/VcsBundle.properties index a7949548f095..905fcad7a049 100644 --- a/platform/platform-resources-en/src/messages/VcsBundle.properties +++ b/platform/platform-resources-en/src/messages/VcsBundle.properties @@ -609,3 +609,7 @@ project.configuration.files.add.notification.action.view=View Files project.configuration.files.add.notification.action.add=Always Add project.configuration.files.add.notification.action.mute=Don't Ask Again +external.files.add.notification.message=Externally added files can be added to {0} +external.files.add.notification.action.view=View Files +external.files.add.notification.action.add=Always Add +external.files.add.notification.action.mute=Don't Ask Again \ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml b/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml index 5e8864721e9c..2729a2a8d2a2 100644 --- a/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml +++ b/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml @@ -81,7 +81,7 @@ - + diff --git a/platform/platform-resources/src/META-INF/JsonPlugin.xml b/platform/platform-resources/src/META-INF/JsonPlugin.xml index 7a286a8e9189..af07db91ced9 100644 --- a/platform/platform-resources/src/META-INF/JsonPlugin.xml +++ b/platform/platform-resources/src/META-INF/JsonPlugin.xml @@ -100,7 +100,7 @@ - + diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index ea1d95a1ecca..a518075f4bc6 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -954,8 +954,8 @@ - - + + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index b1738a0eeaa7..ee1b4c01565b 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -336,5 +336,7 @@ + + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index cbc7ba45f2e9..ac63d8ae7bd1 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -439,11 +439,11 @@ - - - - - + + + + + diff --git a/platform/platform-resources/src/META-INF/VcsExtensions.xml b/platform/platform-resources/src/META-INF/VcsExtensions.xml index e25092e8a54b..7a2635fa4c67 100644 --- a/platform/platform-resources/src/META-INF/VcsExtensions.xml +++ b/platform/platform-resources/src/META-INF/VcsExtensions.xml @@ -38,9 +38,9 @@ - + serviceImplementation="com.intellij.openapi.vcs.changes.IgnoredFileGeneratorImpl$IgnoredFileRootStore"/> + diff --git a/platform/platform-resources/src/META-INF/xdebugger.xml b/platform/platform-resources/src/META-INF/xdebugger.xml index 95cfa203a0f0..cbc5e89578eb 100644 --- a/platform/platform-resources/src/META-INF/xdebugger.xml +++ b/platform/platform-resources/src/META-INF/xdebugger.xml @@ -50,7 +50,7 @@ - + diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index db293581cac2..99be30f44d98 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -139,6 +139,7 @@ + @@ -625,6 +626,7 @@ + diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index 7e2ba7b31cff..bd6a8313ca76 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -912,6 +912,10 @@ + + + + diff --git a/platform/platform-resources/src/keymaps/Sublime Text (Mac OS X).xml b/platform/platform-resources/src/keymaps/Sublime Text (Mac OS X).xml index 00206672262f..d423e9ce4dd8 100644 --- a/platform/platform-resources/src/keymaps/Sublime Text (Mac OS X).xml +++ b/platform/platform-resources/src/keymaps/Sublime Text (Mac OS X).xml @@ -56,6 +56,7 @@ + diff --git a/platform/platform-resources/src/keymaps/Sublime Text.xml b/platform/platform-resources/src/keymaps/Sublime Text.xml index 69b7f7027eea..8f6452fe06fb 100644 --- a/platform/platform-resources/src/keymaps/Sublime Text.xml +++ b/platform/platform-resources/src/keymaps/Sublime Text.xml @@ -62,6 +62,7 @@ + diff --git a/platform/platform-tests/testSrc/com/intellij/internal/statistics/FeatureStatisticsWhitelistTest.kt b/platform/platform-tests/testSrc/com/intellij/internal/statistics/FeatureStatisticsWhitelistTest.kt index 3fb114def4a5..f7fb5249431e 100644 --- a/platform/platform-tests/testSrc/com/intellij/internal/statistics/FeatureStatisticsWhitelistTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/internal/statistics/FeatureStatisticsWhitelistTest.kt @@ -17,6 +17,53 @@ class FeatureStatisticsWhitelistTest { } } + @Test + fun `with build and group version is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "173.4284.118" + }], + "versions" : [ { + "from" : "3", + "to" : "5" + }], + "context" : { + } + }] +} + """ + doTest(content, "IU-173.4284.118", "test.group.id") + } + + @Test + fun `with build and from group version is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "173.4284.118" + }], + "versions" : [ { + "from" : "3" + }], + "context" : { + } + }] +} + """ + doTest(content, "IU-173.4284.118", "test.group.id") + } + @Test fun `with equal build than from is accepted`() { val content = """ @@ -672,6 +719,230 @@ class FeatureStatisticsWhitelistTest { doTest(content, "183.2495", "test.group.id") } + @Test + fun `with from snapshot and build later is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.0" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495", "test.group.id") + } + + @Test + fun `with from snapshot and build later with bugfix update is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.0" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495.245", "test.group.id") + } + + @Test + fun `with from snapshot and build earlier is not accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "191.0" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495") + } + + @Test + fun `with from equals to build is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495", "test.group.id") + } + + @Test + fun `with from middle number equals to build is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495.0", "test.group.id") + } + + @Test + fun `with from middle number equals to build and last is bigger is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495.12", "test.group.id") + } + + @Test + fun `with build middle number equals to from and last is bigger is not accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495.12" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495") + } + + @Test + fun `with build middle number equals to to is not accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495.12", + "to": "183.4885" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.4885") + } + + @Test + fun `with build middle number equals to to and last is bigger is not accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495.12", + "to": "183.4885" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.4885.35") + } + + @Test + fun `with build middle number smaller then to is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495.12", + "to": "183.4885" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.4884.35", "test.group.id") + } + + @Test + fun `with build middle number smaller then to and have two numbers is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495.12", + "to": "183.4885" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.4884", "test.group.id") + } + @Test fun `snapshot builds major greater than from is accepted`() { val content = """ diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/ApplicationImplTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/ApplicationImplTest.java index 48cf16a978d2..0024e9c8feff 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/ApplicationImplTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/ApplicationImplTest.java @@ -135,6 +135,7 @@ public class ApplicationImplTest extends LightPlatformTestCase { } private static void runReadWrites(final int readIterations, final int writeIterations, int expectedMs) { + NonBlockingReadActionImpl.cancelAllTasks(); // someone might've submitted a task depending on app events which we disable now final ApplicationImpl application = (ApplicationImpl)ApplicationManager.getApplication(); Disposable disposable = Disposer.newDisposable(); application.disableEventsUntil(disposable); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/util/io/FileUtilPerformanceTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/util/io/FileUtilPerformanceTest.java index 0c905cb4303d..540e86600e75 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/util/io/FileUtilPerformanceTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/util/io/FileUtilPerformanceTest.java @@ -22,9 +22,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class FileUtilPerformanceTest { - private final String myTestPath = "/a/b/c/./d///e/../f/g/h/i/j/"; - private final String myCanonicalPath = "/a/b/c/d/f/g/h/i/j"; - private final String mySimpleTestPath = "file.txt"; + private static final String myTestPath = "/a/b/c/./d///e/../f/g/h/i/j/"; + private static final String myCanonicalPath = "/a/b/c/d/f/g/h/i/j"; + private static final String mySimpleTestPath = "file.txt"; @Test public void toCanonicalPath() { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilLightTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilLightTest.java index 890de4636846..6e0d1a40c732 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilLightTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilLightTest.java @@ -1,6 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.vfs; import com.intellij.openapi.util.io.FileUtil; @@ -64,7 +62,7 @@ public class VfsUtilLightTest extends BareTestFixtureTestCase { VirtualFile jarRoot = VirtualFileManager.getInstance().findFileByUrl("jar://" + FileUtil.toSystemIndependentName(jarFile.getPath()) + "!/"); assertNotNull(jarRoot); - VFileCreateEvent event = new VFileCreateEvent(this, jarRoot, "x.txt", false, null, false, false); + VFileCreateEvent event = new VFileCreateEvent(this, jarRoot, "x.txt", false, null, null, false, false); assertEquals(FileUtil.toSystemIndependentName(jarFile.getPath()) + "!/x.txt", event.getPath()); } } \ No newline at end of file diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilPerformanceTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilPerformanceTest.java index e79f9378c94f..381b4821d719 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilPerformanceTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilPerformanceTest.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.vfs; import com.intellij.concurrency.JobLauncher; @@ -105,7 +91,7 @@ public class VfsUtilPerformanceTest extends BareTestFixtureTestCase { NewVirtualFile root = ManagingFS.getInstance().findRoot(path, fs); PlatformTestUtil.startPerformanceTest("finding root", 10_000, () -> JobLauncher.getInstance().invokeConcurrentlyUnderProgress( - Collections.nCopies(500, null), null, + Collections.nCopies(500, null), null, __ -> { for (int i = 0; i < 20_000; i++) { NewVirtualFile rootJar = ManagingFS.getInstance().findRoot(path, fs); @@ -194,7 +180,7 @@ public class VfsUtilPerformanceTest extends BareTestFixtureTestCase { public void testAsyncRefresh() throws Throwable { Ref ex = Ref.create(); boolean success = JobLauncher.getInstance().invokeConcurrentlyUnderProgress( - Arrays.asList(new Object[JobSchedulerImpl.getJobPoolParallelism()]), ProgressManager.getInstance().getProgressIndicator(), + Arrays.asList(new Object[JobSchedulerImpl.getJobPoolParallelism()]), ProgressManager.getInstance().getProgressIndicator(), o -> { try { doAsyncRefreshTest(); @@ -332,7 +318,7 @@ public class VfsUtilPerformanceTest extends BareTestFixtureTestCase { events.clear(); TempFileSystem fs = TempFileSystem.getInstance(); IntStream.range(0, N) - .mapToObj(i -> new VFileCreateEvent(this, temp, i + ".txt", false, null, false, false)) + .mapToObj(i -> new VFileCreateEvent(this, temp, i + ".txt", false, null, null, false, false)) .peek(event -> { if (fs.findModelChild(temp, event.getChildName()) == null) { fs.createChildFile(this, temp, event.getChildName()); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerRootsTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerRootsTest.java index 5686d55e0d62..d87c27e01278 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerRootsTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerRootsTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.vfs.impl; import com.intellij.openapi.Disposable; @@ -92,7 +92,7 @@ public class VirtualFilePointerRootsTest extends PlatformTestCase { myVirtualFilePointerManager.shelveAllPointersIn(() -> { for (int i = 0; i < 100_000; i++) { myVirtualFilePointerManager.create(VfsUtilCore.pathToUrl("/a/b/c/d/" + i), disposable, listener); - events.add(new VFileCreateEvent(this, temp, "xxx" + i, false, null, true, false)); + events.add(new VFileCreateEvent(this, temp, "xxx" + i, false, null, null, true, false)); } PlatformTestUtil.startPerformanceTest("vfp update", 7_000, () -> { for (int i = 0; i < 100; i++) { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java index 604a03c3f48a..95cad6a2713d 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.vfs.newvfs.persistent; import com.intellij.openapi.Disposable; @@ -197,11 +197,11 @@ public class PersistentFsTest extends PlatformTestCase { // wrt persistence subDir becomes partially loaded and subsubDir becomes fully loaded File nestedDirOutsideTheProject = new File(projectStructure.getPath() + "../../../"+testName + "/subDir", "subSubDir").getCanonicalFile(); Disposable disposable = null; - + try { boolean atleastSecondRun = nestedDirOutsideTheProject.getParentFile().getParentFile().exists(); StringBuilder eventLog = new StringBuilder(); - + if (atleastSecondRun) { disposable = Disposer.newDisposable(); getProject().getMessageBus().connect(disposable).subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { @@ -219,18 +219,18 @@ public class PersistentFsTest extends PlatformTestCase { } }); } - + // recreating structure will fire vfs removal events VirtualFile nestedDirOutsideTheProjectFile = VfsUtil.createDirectories(nestedDirOutsideTheProject.getPath()); WriteAction.run(() -> nestedDirOutsideTheProjectFile.createChildData(null, "Foo.txt")); - + // subsubDir becomes fully loaded wrt persistence nestedDirOutsideTheProjectFile.getChildren(); if (atleastSecondRun) { - assertEquals("subDir\n" + + assertEquals("subDir\n" + "subDir/subSubDir\n" + - "subDir/subSubDir/Foo.txt\n", + "subDir/subSubDir/Foo.txt\n", eventLog.toString() ); } @@ -240,7 +240,7 @@ public class PersistentFsTest extends PlatformTestCase { FileUtil.delete(nestedDirOutsideTheProject.getParentFile()); } } - + public void testModCountIncreases() throws IOException { VirtualFile vFile = setupFile(); ManagingFS managingFS = ManagingFS.getInstance(); @@ -360,10 +360,10 @@ public class PersistentFsTest extends PlatformTestCase { checkEvents("Before:[VFileCreateEvent->xx.created, VFileDeleteEvent->file.txt]\n" + "After:[VFileCreateEvent->xx.created, VFileDeleteEvent->file.txt]\n", new VFileDeleteEvent(this, vFile, false), - new VFileCreateEvent(this, vFile.getParent(), "xx.created", false, null, false, false), + new VFileCreateEvent(this, vFile.getParent(), "xx.created", false, null, null, false, false), new VFileDeleteEvent(this, vFile, false)); } - + public void testProcessEventsMustGroupDependentEventsCorrectly2() throws IOException { File file = new File(createTempDirectory(), "a/b/c/test.txt"); assertTrue(file.getParentFile().mkdirs()); @@ -377,8 +377,8 @@ public class PersistentFsTest extends PlatformTestCase { "Before:[VFileDeleteEvent->c]\n" + "After:[VFileDeleteEvent->c]\n", new VFileDeleteEvent(this, vFile, false), - new VFileCreateEvent(this, vFile.getParent(), "xx.created", false, null, false, false), - new VFileCreateEvent(this, vFile.getParent(), "xx.created2", false, null, false, false), + new VFileCreateEvent(this, vFile.getParent(), "xx.created", false, null, null, false, false), + new VFileCreateEvent(this, vFile.getParent(), "xx.created2", false, null, null, false, false), new VFileDeleteEvent(this, vFile.getParent(), false)); } diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java b/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java index 2485f1cff967..95bf0a3f603f 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java @@ -1,7 +1,6 @@ // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.components; -import com.intellij.openapi.application.PathManager; import com.intellij.util.ThreeState; import java.lang.annotation.Retention; @@ -12,7 +11,8 @@ import java.lang.annotation.RetentionPolicy; */ @Retention(RetentionPolicy.RUNTIME) public @interface Storage { - String NOT_ROAMABLE_FILE = PathManager.DEFAULT_OPTIONS_FILE; + @Deprecated + String NOT_ROAMABLE_FILE = StoragePathMacros.NOT_ROAMABLE_FILE; /** * @deprecated Use {@link #value()}. diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java b/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java index 0ee9a66fe294..1e2883dca0d0 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java @@ -1,6 +1,7 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.components; +import com.intellij.openapi.application.PathManager; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; @@ -30,6 +31,11 @@ public final class StoragePathMacros { @NotNull public static final String MODULE_FILE = "$MODULE_FILE$"; + /** + * Application level non-roamable storage. + */ + public static final String NOT_ROAMABLE_FILE = PathManager.DEFAULT_OPTIONS_FILE; + private StoragePathMacros() { } } diff --git a/platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/log/TerminalListener.java b/platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/log/TerminalListener.java index bd1590b00cb8..30f3be67e29b 100644 --- a/platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/log/TerminalListener.java +++ b/platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/log/TerminalListener.java @@ -19,7 +19,7 @@ public interface TerminalListener { void close(); - static TerminalListener NULL = new TerminalListener() { + TerminalListener NULL = new TerminalListener() { public void close() { diff --git a/platform/script-debugger/debugger-ui/intellij.platform.scriptDebugger.ui.iml b/platform/script-debugger/debugger-ui/intellij.platform.scriptDebugger.ui.iml index 663770e03d59..1011e9c03742 100644 --- a/platform/script-debugger/debugger-ui/intellij.platform.scriptDebugger.ui.iml +++ b/platform/script-debugger/debugger-ui/intellij.platform.scriptDebugger.ui.iml @@ -15,5 +15,6 @@ +
\ No newline at end of file diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtil.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtil.java index 606919a13c71..3ead3c0aa5e7 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtil.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtil.java @@ -204,7 +204,7 @@ public class TestsPresentationUtil { } String presentationCandidate = name; - if (parent != null) { + if (parent != null && !testProxy.isSuite()) { String parentName = parent.getName(); if (parentName != null) { boolean parentStartsWith = name.startsWith(parentName); diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java index be492214c0d7..0cbac72f76bd 100644 --- a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java +++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java @@ -533,6 +533,23 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { assertEquals(PoolOfTestIcons.PASSED_ICON, renderer2.getIcon()); } + public void testPresentationWithDependentNamesTestProxy() { + SMTestProxy suiteProxy = createSuiteProxy("A"); + SMTestProxy testProxy = createTestProxy("A.b"); + suiteProxy.addChild(testProxy); + TestsPresentationUtil.formatTestProxy(testProxy, myRenderer); + assertEquals("b", myFragContainer.getTextAt(0)); + } + + public void testPresentationWithDependentNamesSuite() { + SMTestProxy suiteProxy = createSuiteProxy("A"); + SMTestProxy suiteProxyChild = createSuiteProxy("AB"); + suiteProxy.addChild(suiteProxyChild); + TestsPresentationUtil.formatTestProxy(suiteProxyChild, myRenderer); + assertEquals("AB", myFragContainer.getTextAt(0)); + myRenderer.clear(); + } + public void testFormatRootNodeWithoutChildren() { TestsPresentationUtil.formatRootNodeWithoutChildren(mySMRootTestProxy, myRenderer); diff --git a/platform/testFramework/extensions/intellij.platform.testExtensions.iml b/platform/testFramework/extensions/intellij.platform.testExtensions.iml index de1623e22634..3b0b46763fda 100644 --- a/platform/testFramework/extensions/intellij.platform.testExtensions.iml +++ b/platform/testFramework/extensions/intellij.platform.testExtensions.iml @@ -3,16 +3,16 @@ - + - - - - - - - + + + + + + +
\ No newline at end of file diff --git a/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java b/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java index 74962d37f166..c577be148754 100644 --- a/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java +++ b/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java @@ -391,6 +391,7 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase { "ActivateStructureToolWindow", "ActivateTODOToolWindow", "ActivateWebToolWindow", "ActivatePaletteToolWindow", "ActivateTerminalToolWindow", "IDEtalk.SearchUserHistory", "IDEtalk.SearchUserHistory", "IDEtalk.Rename", + "CIDR.Lang.Cpp.GenerateDefinitions", "" ); diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/IoTestUtil.java b/platform/testFramework/src/com/intellij/openapi/util/io/IoTestUtil.java similarity index 100% rename from platform/util/testSrc/com/intellij/openapi/util/io/IoTestUtil.java rename to platform/testFramework/src/com/intellij/openapi/util/io/IoTestUtil.java diff --git a/platform/testFramework/src/com/intellij/testFramework/CpuTimings.java b/platform/testFramework/src/com/intellij/testFramework/CpuTimings.java index 64ff7eff1161..5492805224ae 100644 --- a/platform/testFramework/src/com/intellij/testFramework/CpuTimings.java +++ b/platform/testFramework/src/com/intellij/testFramework/CpuTimings.java @@ -38,7 +38,7 @@ class CpuTimings { StringBuilder log = new StringBuilder(); for (int i = 0;; i++) { - long time = TimeoutUtil.runAndGetExecutionTime(CpuTimings::addBigIntegers); + long time = TimeoutUtil.measureExecutionTime(CpuTimings::addBigIntegers); if (time < minTime) { //log.append("Iteration " + i + ", time " + time + "\n"); minTime = time; diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index 773f58a05ef3..cf375580d16e 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -17,6 +17,7 @@ import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.application.impl.LaterInvocator; +import com.intellij.openapi.application.impl.NonBlockingReadActionImpl; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.command.impl.DocumentReferenceManagerImpl; @@ -24,7 +25,6 @@ import com.intellij.openapi.command.impl.UndoManagerImpl; import com.intellij.openapi.command.undo.DocumentReferenceManager; import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileEditor.impl.text.AsyncHighlighterUpdater; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl; import com.intellij.openapi.module.EmptyModuleType; @@ -458,7 +458,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro ((PsiManagerImpl)PsiManager.getInstance(defaultProject)).cleanupForNextTest(); } - AsyncHighlighterUpdater.completeAsyncTasks(); + NonBlockingReadActionImpl.cancelAllTasks(); ((FileBasedIndexImpl) FileBasedIndex.getInstance()).cleanupForNextTest(); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java index ff0c2e169944..004e3d9824ee 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.testFramework.fixtures.impl; @@ -57,7 +57,11 @@ public class LightIdeaTestFixtureImpl extends BaseFixture implements LightIdeaTe myCodeStyleSettingsTracker.checkForSettingsDamage(); } }) - .append(() -> PlatformTestCase.waitForProjectLeakingThreads(project, 10, TimeUnit.SECONDS)) + .append(() -> { + if (project != null) { + PlatformTestCase.waitForProjectLeakingThreads(project, 10, TimeUnit.SECONDS); + } + }) .append(() -> super.tearDown()) // call all disposables' dispose() while the project is still open .append(() -> { if (project != null) { diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/GutterFixture.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/GutterFixture.kt index 76b420cb8944..7eddff3ee613 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/GutterFixture.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/GutterFixture.kt @@ -24,7 +24,9 @@ open class GutterFixture(private val myIde: IdeFrameFixture) { IMPLEMENTATION, IMPLEMENTED, OVERRIDES, - OVERRIDDEN + OVERRIDDEN, + PASSED, + FAILED } val gutterIcons: Map> @@ -52,6 +54,8 @@ open class GutterFixture(private val myIde: IdeFrameFixture) { AllIcons.RunConfigurations.TestState.Run -> result[GutterIcon.RUN_SCRIPT]!!.add(lineNumber) AllIcons.Debugger.Db_set_breakpoint -> result[GutterIcon.BREAKPOINT]!!.add(lineNumber) AllIcons.Debugger.Db_disabled_breakpoint -> result[GutterIcon.DISABLED_BREAKPOINT]!!.add(lineNumber) + AllIcons.RunConfigurations.TestState.Green2 -> result[GutterIcon.PASSED]!!.add(lineNumber) + AllIcons.RunConfigurations.TestState.Red2 -> result[GutterIcon.FAILED]!!.add(lineNumber) else -> handleUnmatchedIcon(icon)?.let { result.getOrDefault(it, mutableListOf(lineNumber)).add(lineNumber) } } } diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestCaseExt.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestCaseExt.kt index f95c34819aec..ecd85cc2b7d9 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestCaseExt.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestCaseExt.kt @@ -343,6 +343,7 @@ fun GuiTestCase.checkGutterIcons(gutterIcon: GutterFixture.GutterIcon, waitUntilFileIsLoaded() waitUntilErrorAnalysisFinishes() gutter.waitUntilIconsShown(mapOf(gutterIcon to expectedNumberOfIcons)) + moveToLine(expectedNumberOfIcons) } val gutterLinesWithIcon = gutter.linesWithGutterIcon(gutterIcon) val contents = this@editor.getCurrentFileContents(false)?.lines() ?: listOf() diff --git a/platform/util/src/com/intellij/icons/AllIcons.java b/platform/util/src/com/intellij/icons/AllIcons.java index 941b376cc8be..fea431de0d13 100644 --- a/platform/util/src/com/intellij/icons/AllIcons.java +++ b/platform/util/src/com/intellij/icons/AllIcons.java @@ -484,6 +484,10 @@ public class AllIcons { * 16x16 */ public static final Icon StepOut = IconLoader.getIcon("/actions/stepOut.svg"); + /** + * 16x16 + */ + public static final Icon StepOutCodeBlock = IconLoader.getIcon("/actions/stepOutCodeBlock.svg"); /** * 16x16 */ diff --git a/platform/util/src/com/intellij/openapi/util/IntRef.java b/platform/util/src/com/intellij/openapi/util/IntRef.java new file mode 100644 index 000000000000..3a29df8b8110 --- /dev/null +++ b/platform/util/src/com/intellij/openapi/util/IntRef.java @@ -0,0 +1,31 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.util; + +public class IntRef { + private int myValue; + + public IntRef() { + this(0); + } + + public IntRef(int value) { + myValue = value; + } + + public int get() { + return myValue; + } + + public void set(int value) { + myValue = value; + } + + public void inc() { + myValue++; + } + + @Override + public String toString() { + return "IntRef(" + myValue + ")"; + } +} diff --git a/platform/util/src/com/intellij/util/ObjectUtils.java b/platform/util/src/com/intellij/util/ObjectUtils.java index 0d06d32cfb71..b49c56372335 100644 --- a/platform/util/src/com/intellij/util/ObjectUtils.java +++ b/platform/util/src/com/intellij/util/ObjectUtils.java @@ -60,6 +60,8 @@ public class ObjectUtils { if (!ofInterface.isInterface()) { throw new IllegalArgumentException("Expected interface but got: " + ofInterface); } + // java.lang.reflect.Proxy.ProxyClassFactory fails if the class is not available via the classloader. + // We must use interface own classloader because classes from plugins are not available via ObjectUtils' classloader. //noinspection unchecked return (T)Proxy.newProxyInstance(ofInterface.getClassLoader(), new Class[]{ofInterface}, new InvocationHandler() { @Override diff --git a/platform/util/src/com/intellij/util/TimeoutUtil.java b/platform/util/src/com/intellij/util/TimeoutUtil.java index 049b9e452192..0c8f4d17f332 100644 --- a/platform/util/src/com/intellij/util/TimeoutUtil.java +++ b/platform/util/src/com/intellij/util/TimeoutUtil.java @@ -69,7 +69,7 @@ public final class TimeoutUtil { * @return time of running {@code runnable} in milliseconds */ @ApiStatus.Experimental - public static long runAndGetExecutionTime(@NotNull ThrowableRunnable runnable) throws E { + public static long measureExecutionTime(@NotNull ThrowableRunnable runnable) throws E { long startTime = System.currentTimeMillis(); runnable.run(); return System.currentTimeMillis() - startTime; diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentLongObjectMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentLongObjectMap.java index db992680c023..a848c7284bcb 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentLongObjectMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentLongObjectMap.java @@ -82,7 +82,7 @@ public interface ConcurrentLongObjectMap { boolean isEmpty(); @NotNull - public Enumeration elements(); + Enumeration elements(); @NotNull Collection values(); boolean containsValue(@NotNull V value); diff --git a/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java b/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java index a85eaa40e85d..c757caeba542 100644 --- a/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java +++ b/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java @@ -64,7 +64,7 @@ public class AppendableStorageBackedByResizableMappedFile extends ResizeableMapp } private final CompressedAppendableFile myCompressedAppendableFile; - private final boolean testMode = false; + private static final boolean testMode = false; public Data read(final int addr, KeyDescriptor descriptor) throws IOException { Data tempData = null; diff --git a/platform/util/src/com/intellij/util/io/IntToIntBtree.java b/platform/util/src/com/intellij/util/io/IntToIntBtree.java index f790c0485c0b..d423189a4937 100644 --- a/platform/util/src/com/intellij/util/io/IntToIntBtree.java +++ b/platform/util/src/com/intellij/util/io/IntToIntBtree.java @@ -52,10 +52,10 @@ public class IntToIntBtree { private boolean hasZeroKey; private int zeroKeyValue; - private final boolean isLarge = true; + private static final boolean isLarge = true; private final ResizeableMappedFile storage; - private final boolean offloadToSiblingsBeforeSplit = false; - private final boolean indexNodeIsHashTable = true; + private static final boolean offloadToSiblingsBeforeSplit = false; + private static final boolean indexNodeIsHashTable = true; final int metaDataLeafPageLength; final int hashPageCapacity; diff --git a/platform/util/src/com/intellij/util/keyFMap/KeyFMap.java b/platform/util/src/com/intellij/util/keyFMap/KeyFMap.java index 4971f9914b50..1b388dbb824d 100644 --- a/platform/util/src/com/intellij/util/keyFMap/KeyFMap.java +++ b/platform/util/src/com/intellij/util/keyFMap/KeyFMap.java @@ -1,21 +1,8 @@ -/* - * 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. - */ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.util.keyFMap; import com.intellij.openapi.util.Key; +import org.jetbrains.annotations.Debugger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,6 +17,7 @@ import org.jetbrains.annotations.Nullable; * * @author peter */ +@Debugger.Renderer(text = "\"size = \" + size()", hasChildren = "!isEmpty()", childrenArray = "KeyFMapRenderer.childrenArray(this)") public interface KeyFMap { /** * An empty {@code KeyFMap}. No additional instances of empty {@code KeyFMap} should be created as they are indistinguishable. diff --git a/platform/util/src/com/intellij/util/keyFMap/KeyFMapRenderer.java b/platform/util/src/com/intellij/util/keyFMap/KeyFMapRenderer.java new file mode 100644 index 000000000000..5b7151a93d84 --- /dev/null +++ b/platform/util/src/com/intellij/util/keyFMap/KeyFMapRenderer.java @@ -0,0 +1,22 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.util.keyFMap; + +import com.intellij.openapi.util.Key; + +import java.util.AbstractMap; +import java.util.Map; + +// Used in KeyFMap debugger renderer +@SuppressWarnings("unused") +class KeyFMapRenderer { + static Map.Entry[] childrenArray(KeyFMap map) { + Key[] keys = map.getKeys(); + int length = map.size(); + Map.Entry[] res = new Map.Entry[length]; + for (int i = 0; i < length; i++) { + Key key = keys[i]; + res[i] = new AbstractMap.SimpleImmutableEntry(key, map.get(key)); + } + return res; + } +} diff --git a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java index 5e98c607ff28..a3d146d85311 100644 --- a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java +++ b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java @@ -63,7 +63,7 @@ public class WideSelectionTreeUI extends BasicTreeUI { private final boolean myWideSelection; private boolean myOldRepaintAllRowValue; private boolean myForceDontPaintLines = false; - private final boolean mySkinny = false; + private static final boolean mySkinny = false; public WideSelectionTreeUI() { this(true, Conditions.alwaysTrue()); diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessor.java b/platform/vcs-api/src/com/intellij/openapi/vcs/FilesProcessor.java similarity index 79% rename from platform/vcs-api/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessor.java rename to platform/vcs-api/src/com/intellij/openapi/vcs/FilesProcessor.java index 4ab2bb25abd2..a48cc89e83ab 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessor.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/FilesProcessor.java @@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull; import java.util.List; -public interface ProjectConfigurationFilesProcessor { +public interface FilesProcessor { @NotNull - List processFiles(@NotNull List files, @NotNull VcsVFSListener listener); + List processFiles(@NotNull List files); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ExternallyAddedFilesProcessorImpl.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/ExternallyAddedFilesProcessorImpl.kt new file mode 100644 index 000000000000..b393126fdd01 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ExternallyAddedFilesProcessorImpl.kt @@ -0,0 +1,34 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.vcs + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile + +private const val ADD_EXTERNAL_FILES_PROPERTY = "ADD_EXTERNAL_FILES" +private const val ASKED_ADD_EXTERNAL_FILES_PROPERTY = "ASKED_ADD_EXTERNAL_FILES" + +class ExternallyAddedFilesProcessorImpl(project: Project, + private val vcsName: String, + private val addChosenFiles: (Collection) -> Unit) + : FilesProcessorWithNotificationImpl(project), FilesProcessor { + + override val askedBeforeProperty = ASKED_ADD_EXTERNAL_FILES_PROPERTY + override val doForCurrentProjectProperty = ADD_EXTERNAL_FILES_PROPERTY + + override val showActionText: String = VcsBundle.message("external.files.add.notification.action.view") + override val forCurrentProjectActionText: String = VcsBundle.message("external.files.add.notification.action.add") + override val forAllProjectsActionText: String? = null + override val muteActionText: String = VcsBundle.message("external.files.add.notification.action.mute") + + override fun notificationTitle() = "" + + override fun notificationMessage(): String = VcsBundle.message("external.files.add.notification.message", vcsName) + + override fun doActionOnChosenFiles(files: Collection) { + addChosenFiles(files) + } + + override fun doFilterFiles(files: Collection) = files + + override fun rememberForAllProjects() {} +} \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/FilesProcessorWithNotificationImpl.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/FilesProcessorWithNotificationImpl.kt new file mode 100644 index 000000000000..ca3fc1fd0157 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/FilesProcessorWithNotificationImpl.kt @@ -0,0 +1,152 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.vcs + +import com.intellij.CommonBundle +import com.intellij.ide.util.PropertiesComponent +import com.intellij.notification.Notification +import com.intellij.notification.NotificationAction +import com.intellij.openapi.project.Project +import com.intellij.openapi.vcs.changes.ui.SelectFilesDialog +import com.intellij.openapi.vfs.VirtualFile + +abstract class FilesProcessorWithNotificationImpl(protected val project: Project) : FilesProcessor { + + private val vcsNotifier = VcsNotifier.getInstance(project) + + private val projectProperties = PropertiesComponent.getInstance(project) + + private val files = mutableSetOf() + + private val NOTIFICATION_LOCK = Object() + + private var notification: Notification? = null + + abstract val askedBeforeProperty: String + + abstract val doForCurrentProjectProperty: String + + abstract val showActionText: String + abstract val forCurrentProjectActionText: String + abstract val forAllProjectsActionText: String? + abstract val muteActionText: String + + abstract fun notificationTitle(): String + abstract fun notificationMessage(): String + + abstract fun doActionOnChosenFiles(files: Collection) + + abstract fun doFilterFiles(files: Collection): Collection + + abstract fun rememberForAllProjects() + + override fun processFiles(files: List): List { + + val filteredFiles = doFilterFiles(files) + + if (filteredFiles.isEmpty()) return files + + addNewFiles(filteredFiles) + + if (needDoForCurrentProject()) { + doActionOnChosenFiles(acquireValidFiles()) + } + else { + proposeToProcessFiles() + } + + return files - filteredFiles + } + + private fun proposeToProcessFiles() { + synchronized(NOTIFICATION_LOCK) { + if (notAskedBefore() && notificationNotPresent()) { + val notificationActions = mutableListOf(showAction(), addForCurrentProjectAction()).apply { + if (forAllProjectsActionText != null) { + add(forAllProjectsAction()) + } + add(muteAction()) + } + notification = vcsNotifier.notifyMinorInfo(true, notificationTitle(), notificationMessage(), *notificationActions.toTypedArray()) + } + } + } + + @Synchronized + private fun removeFiles(filesToRemove: Collection) { + files.removeAll(filesToRemove) + } + + @Synchronized + private fun isFilesEmpty() = files.isEmpty() + + @Synchronized + private fun addNewFiles(filesToAdd: Collection) { + files.addAll(filesToAdd) + } + + @Synchronized + private fun acquireValidFiles(): List { + files.removeAll { !it.isValid } + return files.toList() + } + + @Synchronized + private fun clearFiles() { + files.clear() + } + + private fun showAction() = NotificationAction.createSimple(showActionText) { + val allFiles = acquireValidFiles() + if (allFiles.isNotEmpty()) { + with(SelectFilesDialog.init(project, allFiles, null, null, true, true, + CommonBundle.getAddButtonText(), CommonBundle.getCancelButtonText())) { + selectedFiles = allFiles + if (showAndGet()) { + val userSelectedFiles = selectedFiles + doActionOnChosenFiles(userSelectedFiles) + removeFiles(userSelectedFiles) + if (isFilesEmpty()) { + expireNotification() + } + } + } + } + } + + private fun addForCurrentProjectAction() = NotificationAction.create(forCurrentProjectActionText) { _, _ -> + doActionOnChosenFiles(acquireValidFiles()) + projectProperties.setValue(doForCurrentProjectProperty, true) + projectProperties.setValue(askedBeforeProperty, true) + expireNotification() + clearFiles() + } + + private fun forAllProjectsAction() = NotificationAction.create(forAllProjectsActionText!!) { _, _ -> + doActionOnChosenFiles(acquireValidFiles()) + projectProperties.setValue(doForCurrentProjectProperty, true) + projectProperties.setValue(askedBeforeProperty, true) + rememberForAllProjects() + expireNotification() + clearFiles() + } + + private fun muteAction() = NotificationAction.create(muteActionText) { _, notification -> + projectProperties.setValue(doForCurrentProjectProperty, false) + projectProperties.setValue(askedBeforeProperty, true) + notification.expire() + } + + private fun notificationNotPresent() = + synchronized(NOTIFICATION_LOCK) { + notification?.isExpired ?: true + } + + private fun expireNotification() = + synchronized(NOTIFICATION_LOCK) { + notification?.expire() + } + + private fun notAskedBefore() = !projectProperties.getBoolean(askedBeforeProperty, false) + + private fun needDoForCurrentProject() = projectProperties.getBoolean(doForCurrentProjectProperty, false) +} \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessorImpl.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessorImpl.kt index 18a51ec5971c..98f93bd8aabc 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessorImpl.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessorImpl.kt @@ -1,15 +1,11 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.vcs -import com.intellij.CommonBundle import com.intellij.ide.highlighter.ModuleFileType import com.intellij.ide.highlighter.ProjectFileType -import com.intellij.ide.util.PropertiesComponent -import com.intellij.notification.Notification -import com.intellij.notification.NotificationAction +import com.intellij.openapi.components.* import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project -import com.intellij.openapi.vcs.changes.ui.SelectFilesDialog import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile @@ -19,134 +15,92 @@ import com.intellij.util.containers.ContainerUtil private val LOG = Logger.getInstance(ProjectConfigurationFilesProcessorImpl::class.java) -private val configurationFilesExtensionsOutsideStoreDirectory = ContainerUtil.newHashSet( - ProjectFileType.DEFAULT_EXTENSION, - ModuleFileType.DEFAULT_EXTENSION) +private val configurationFilesExtensionsOutsideStoreDirectory = + ContainerUtil.newHashSet(ProjectFileType.DEFAULT_EXTENSION, ModuleFileType.DEFAULT_EXTENSION) private const val SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY = "SHARE_PROJECT_CONFIGURATION_FILES" private const val ASKED_SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY = "ASKED_SHARE_PROJECT_CONFIGURATION_FILES" -class ProjectConfigurationFilesProcessorImpl(private val project: Project, - private val vcsNotifier: VcsNotifier, - private val propertiesComponent: PropertiesComponent) : ProjectConfigurationFilesProcessor { +class ProjectConfigurationFilesProcessorImpl(project: Project, + private val vcsName: String, + private val addChosenFiles: (Collection) -> Unit) + : FilesProcessorWithNotificationImpl(project), FilesProcessor { - private val files = mutableSetOf() + private val fileSystem = LocalFileSystem.getInstance() - private val NOTIFICATION_LOCK = Object() + private val projectConfigurationFilesStore = getProjectConfigurationFilesStore(project) - private var notification: Notification? = null - - override fun processFiles(files: List, listener: VcsVFSListener): List { + override fun doFilterFiles(files: Collection): Collection { val projectBasePath = project.basePath ?: return files - val projectBaseDir = LocalFileSystem.getInstance().findFileByPath(projectBasePath) ?: return files + val projectBaseDir = fileSystem.findFileByPath(projectBasePath) ?: return files val storeDir = getProjectStoreDirectory(projectBaseDir) if (project.isDirectoryBased && storeDir == null) { LOG.warn("Cannot find store directory for project in directory ${projectBaseDir.path}") return files } - val projectConfigurationFiles = files.filter { + val filteredFiles = files.filter { configurationFilesExtensionsOutsideStoreDirectory.contains(it.extension) || isProjectConfigurationFile(storeDir, it) } - if (projectConfigurationFiles.isEmpty()) return files + val previouslyStoredFiles = projectConfigurationFilesStore.cleanupAndGetValidFiles() + projectConfigurationFilesStore.addAll(filteredFiles) - addNewFiles(projectConfigurationFiles) - - if (needShareFiles()) { - listener.performAdding(acquireValidFiles(), emptyMap()) - } - else { - proposeAddFilesToVcs(listener) - } - - return files - projectConfigurationFiles + return filteredFiles + previouslyStoredFiles } - private fun proposeAddFilesToVcs(listener: VcsVFSListener) { - synchronized(NOTIFICATION_LOCK) { - if (notAskedToShareFiles() && notificationNotPresent()) { - notification = vcsNotifier.notifyMinorInfo("", - VcsBundle.message("project.configuration.files.add.notification.message", - listener.myVcs.displayName), - showAction(listener), addAction(listener), muteAction()) - } - } + override fun doActionOnChosenFiles(files: Collection) { + addChosenFiles(files) + projectConfigurationFilesStore.removeAll(files) } - private fun showAction(listener: VcsVFSListener) = NotificationAction.createSimple( - VcsBundle.getString("project.configuration.files.add.notification.action.view")) { - val allProjectFiles = acquireValidFiles() - if (allProjectFiles.isNotEmpty()) { - with(SelectFilesDialog.init(project, allProjectFiles, null, null, true, true, - CommonBundle.getAddButtonText(), CommonBundle.getCancelButtonText())) { - selectedFiles = allProjectFiles - if (showAndGet()) { - val userSelectedFiles = selectedFiles - listener.performAdding(userSelectedFiles, emptyMap()) - removeFiles(userSelectedFiles) - if(isFilesEmpty()){ - expireNotification() - } - } - } - } - } + override val askedBeforeProperty = ASKED_SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY - @Synchronized - private fun removeFiles(projectConfigurationFiles: Collection) { - files.removeAll(projectConfigurationFiles) - } + override val doForCurrentProjectProperty = SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY - @Synchronized - private fun isFilesEmpty() = files.isEmpty() + override fun notificationTitle() = "" - @Synchronized - private fun addNewFiles(projectConfigurationFiles: Collection) { - files.addAll(projectConfigurationFiles) - } + override fun notificationMessage(): String = VcsBundle.message("project.configuration.files.add.notification.message", vcsName) + override val showActionText: String = VcsBundle.getString("project.configuration.files.add.notification.action.view") - @Synchronized - private fun acquireValidFiles(): List { - files.removeAll { !it.isValid } - return files.toList() - } - @Synchronized - private fun clearFiles() { - files.clear() - } + override val forCurrentProjectActionText: String = VcsBundle.getString("project.configuration.files.add.notification.action.add") + override val forAllProjectsActionText: String? = null + override val muteActionText: String = VcsBundle.getString("project.configuration.files.add.notification.action.mute") - private fun addAction(listener: VcsVFSListener) = NotificationAction.create( - VcsBundle.getString("project.configuration.files.add.notification.action.add")) { _, _ -> - listener.performAdding(acquireValidFiles(), emptyMap()) - propertiesComponent.setValue(SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY, true) - propertiesComponent.setValue(ASKED_SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY, true) - expireNotification() - clearFiles() - } - - private fun muteAction() = NotificationAction.create( - VcsBundle.getString("project.configuration.files.add.notification.action.mute")) { _, notification -> - propertiesComponent.setValue(SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY, false) - propertiesComponent.setValue(ASKED_SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY, true) - notification.expire() - } - - private fun notificationNotPresent() = - synchronized(NOTIFICATION_LOCK) { - notification?.isExpired ?: true - } - - private fun expireNotification() = - synchronized(NOTIFICATION_LOCK) { - notification?.expire() - } + override fun rememberForAllProjects() {} private fun isProjectConfigurationFile(storeDir: VirtualFile?, file: VirtualFile) = storeDir != null && VfsUtilCore.isAncestor(storeDir, file, true) +} - private fun notAskedToShareFiles() = !propertiesComponent.getBoolean(ASKED_SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY, false) +@State(name = "ProjectConfigurationFiles", storages = [Storage(StoragePathMacros.WORKSPACE_FILE)]) +class ProjectConfigurationFilesStoreState : PersistentStateComponent { - private fun needShareFiles() = propertiesComponent.getBoolean(SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY, false) -} \ No newline at end of file + private val fileSystem = LocalFileSystem.getInstance() + + data class State(var files: MutableList = mutableListOf()) + + var myState = State() + + fun cleanupAndGetValidFiles(): List { + val validFiles = state.files.mapNotNull { fileSystem.findFileByPath(it)} + state.files.retainAll(validFiles.map { it.path }) + return validFiles + } + + fun addAll(files: Collection) = + state.files.addAll(files.map(VirtualFile::getPath)) + + fun removeAll(files: Collection) = + state.files.removeAll(files.map(VirtualFile::getPath)) + + override fun getState() = myState + + override fun loadState(state: State) { + myState = state + } +} + +fun getProjectConfigurationFilesStore(project: Project): ProjectConfigurationFilesStoreState = + ServiceManager.getService(project, ProjectConfigurationFilesStoreState::class.java) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsNotifier.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsNotifier.java index 68bb4c80cb42..4f9c6dec661e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsNotifier.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsNotifier.java @@ -180,6 +180,11 @@ public class VcsNotifier { return notify(STANDARD_NOTIFICATION, title, message, NotificationType.INFORMATION, actions); } + @NotNull + public Notification notifyMinorInfo(boolean sticky, @NotNull String title, @NotNull String message, NotificationAction... actions) { + return notify(sticky ? IMPORTANT_ERROR_NOTIFICATION : STANDARD_NOTIFICATION, title, message, NotificationType.INFORMATION, actions); + } + public Notification logInfo(@NotNull String title, @NotNull String message) { return notify(SILENT_NOTIFICATION, title, message, NotificationType.INFORMATION); } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java similarity index 85% rename from platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java rename to platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java index b85f43ba5ae6..5110254285d2 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java @@ -1,11 +1,10 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.vcs; import com.intellij.openapi.Disposable; import com.intellij.openapi.command.CommandEvent; import com.intellij.openapi.command.CommandListener; -import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; @@ -19,12 +18,15 @@ import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcsUtil.VcsUtil; +import kotlin.Unit; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.*; +import static java.util.Collections.emptyMap; + public abstract class VcsVFSListener implements Disposable { protected static final Logger LOG = Logger.getInstance(VcsVFSListener.class); @@ -62,7 +64,8 @@ public abstract class VcsVFSListener implements Disposable { protected final List myDeletedFiles = new ArrayList<>(); protected final List myDeletedWithoutConfirmFiles = new ArrayList<>(); protected final List myMovedFiles = new ArrayList<>(); - private final ProjectConfigurationFilesProcessor myProjectConfigurationFilesProcessor; + private final FilesProcessor myProjectConfigurationFilesProcessor; + private final FilesProcessor myExternalFilesProcessor; protected enum VcsDeleteType {SILENT, CONFIRM, IGNORE} @@ -79,7 +82,8 @@ public abstract class VcsVFSListener implements Disposable { project.getMessageBus().connect(this).subscribe(CommandListener.TOPIC, new MyCommandAdapter()); myVcsFileListenerContextHelper = VcsFileListenerContextHelper.getInstance(myProject); - myProjectConfigurationFilesProcessor = ServiceManager.getService(myProject, ProjectConfigurationFilesProcessor.class); + myProjectConfigurationFilesProcessor = createProjectConfigurationFilesProcessor(); + myExternalFilesProcessor = createExternalFilesProcessor(); } @Override @@ -91,6 +95,10 @@ public abstract class VcsVFSListener implements Disposable { return !isUnderMyVcs(event.getFile()); } + private static boolean isExternalEvent(@NotNull VirtualFileEvent event) { + return event.isFromRefresh(); + } + private boolean isUnderMyVcs(@NotNull VirtualFile file) { return myVcsManager.getVcsFor(file) == myVcs && myVcsManager.isFileInContent(file) && @@ -137,7 +145,7 @@ public abstract class VcsVFSListener implements Disposable { LOG.debug("executeAdd. add-option: ", myAddOption.getValue(), ", files to add: ", addedFiles); if (myAddOption.getValue() == VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) return; - addedFiles = myProjectConfigurationFilesProcessor.processFiles(addedFiles, this); + addedFiles = myProjectConfigurationFilesProcessor.processFiles(addedFiles); if (myAddOption.getValue() == VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY) { performAdding(addedFiles, copyFromMap); @@ -154,6 +162,17 @@ public abstract class VcsVFSListener implements Disposable { } } + protected void executeAddWithoutIgnores(@NotNull List addedFiles, + @NotNull Map copyFromMap, + @NotNull ExecuteAddCallback executeAddCallback) { + executeAddCallback.executeAdd(addedFiles, copyFromMap); + } + + @FunctionalInterface + protected interface ExecuteAddCallback { + void executeAdd(@NotNull List addedFiles, @NotNull Map copyFromMap); + } + protected void saveUnsavedVcsIgnoreFiles() { FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); Set ignoreFileNames = VcsUtil.getVcsIgnoreFileNames(myProject); @@ -227,10 +246,20 @@ public abstract class VcsVFSListener implements Disposable { } protected void fileAdded(@NotNull VirtualFileEvent event, @NotNull VirtualFile file) { - if (!isEventIgnored(event) && !myChangeListManager.isIgnoredFile(file) && + if (isExternalEvent(event) + && !myChangeListManager.isIgnoredFile(file) && VcsUtil.getVcsRootFor(myProject, file) != null) { + LOG.debug("Adding external file [", file, "]"); + if (file.isDirectory()) { + processExternalCreatedFiles(ContainerUtil.newArrayList(file)); + } else { + executeAddWithoutIgnores(ContainerUtil.newArrayList(file), Collections.emptyMap(), + (notIgnoredFiles, copiedFilesMap) -> processExternalCreatedFiles(notIgnoredFiles)); + } + } + else if (!isEventIgnored(event) && (isDirectoryVersioningSupported() || !file.isDirectory())) { LOG.debug("Adding [", file, "] to added files"); - myAddedFiles.add(event.getFile()); + myAddedFiles.add(file); } } @@ -316,6 +345,26 @@ public abstract class VcsVFSListener implements Disposable { protected abstract boolean isDirectoryVersioningSupported(); + @SuppressWarnings("unchecked") + private FilesProcessor createExternalFilesProcessor() { + return new ExternallyAddedFilesProcessorImpl(myProject, + myVcs.getDisplayName(), + (files) -> { + performAdding((Collection)files, emptyMap()); + return Unit.INSTANCE; + }); + } + + @SuppressWarnings("unchecked") + private FilesProcessor createProjectConfigurationFilesProcessor() { + return new ProjectConfigurationFilesProcessorImpl(myProject, + myVcs.getDisplayName(), + (files) -> { + performAdding((Collection)files, emptyMap()); + return Unit.INSTANCE; + }); + } + private class MyVirtualFileListener implements VirtualFileListener { @Override public void fileCreated(@NotNull final VirtualFileEvent event) { @@ -413,6 +462,20 @@ public abstract class VcsVFSListener implements Disposable { } } + private void processExternalCreatedFiles(@NotNull List files) { + if (myAddOption.getValue() == VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) return; + + files = myProjectConfigurationFilesProcessor.processFiles(files); + if (files.isEmpty()) return; + + if (myAddOption.getValue() == VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY) { + performAdding(files, Collections.emptyMap()); + } + else { + myExternalFilesProcessor.processFiles(files); + } + } + private class MyCommandAdapter implements CommandListener { private int myCommandLevel; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateLocalFileAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateLocalFileAction.java index a341bb53c695..f39b58c930a6 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateLocalFileAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateLocalFileAction.java @@ -29,6 +29,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.annotate.AnnotationProvider; @@ -99,8 +100,10 @@ public class AnnotateLocalFileAction { } if (editor == null) { - LOG.error(String.format("Can't create text editor for file: valid - %s; file type - %s; editors - %s", - selectedFile.isValid(), selectedFile.getFileType(), Arrays.toString(fileEditors))); + Messages.showErrorDialog(project, "Can't create text editor for " + selectedFile.getPresentableUrl(), + VcsBundle.message("message.title.annotate")); + LOG.warn(String.format("Can't create text editor for file: valid - %s; file type - %s; editors - %s", + selectedFile.isValid(), selectedFile.getFileType().getName(), Arrays.toString(fileEditors))); return; } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsFileStatusProvider.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsFileStatusProvider.java index 34c689c0cfb2..dbc7f1bd35da 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsFileStatusProvider.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsFileStatusProvider.java @@ -23,6 +23,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.*; +import com.intellij.openapi.vcs.diff.DiffProvider; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vcs.readOnlyHandler.ReadonlyStatusHandlerImpl; import com.intellij.openapi.vcs.rollback.RollbackEnvironment; @@ -148,11 +149,26 @@ public class VcsFileStatusProvider implements FileStatusProvider, VcsBaseContent VcsBaseContentProvider provider = findProviderFor(file); return provider == null ? null : provider.getBaseRevision(file); } - final Change change = ChangeListManager.getInstance(myProject).getChange(file); - if (change == null) return null; - final ContentRevision beforeRevision = change.getBeforeRevision(); - if (beforeRevision == null) return null; - return new BaseContentImpl(beforeRevision); + + ChangeListManager changeListManager = ChangeListManager.getInstance(myProject); + + Change change = changeListManager.getChange(file); + if (change != null) { + ContentRevision beforeRevision = change.getBeforeRevision(); + return beforeRevision == null ? null : new BaseContentImpl(beforeRevision); + } + + FileStatus status = changeListManager.getStatus(file); + if (status == FileStatus.HIJACKED) { + AbstractVcs vcs = ProjectLevelVcsManager.getInstance(myProject).getVcsFor(file); + DiffProvider diffProvider = vcs != null ? vcs.getDiffProvider() : null; + if (diffProvider != null) { + VcsRevisionNumber currentRevision = diffProvider.getCurrentRevision(file); + return currentRevision == null ? null : new HijackedBaseContent(diffProvider, file, currentRevision); + } + } + + return null; } @Nullable @@ -188,26 +204,59 @@ public class VcsFileStatusProvider implements FileStatusProvider, VcsBaseContent @Nullable @Override public String loadContent() { - try { - if (myContentRevision instanceof ByteBackedContentRevision) { - byte[] revisionContent = ((ByteBackedContentRevision)myContentRevision).getContentAsBytes(); - FilePath filePath = myContentRevision.getFile(); + return loadContentRevision(myContentRevision); + } + } - if (revisionContent != null) { - Charset charset = DiffContentFactoryImpl.guessCharset(revisionContent, filePath); - return CharsetToolkit.decodeString(revisionContent, charset); - } - else { - return null; - } + private static class HijackedBaseContent implements BaseContent { + @NotNull private final DiffProvider myDiffProvider; + @NotNull private final VirtualFile myFile; + @NotNull private final VcsRevisionNumber myRevision; + + HijackedBaseContent(@NotNull DiffProvider diffProvider, + @NotNull VirtualFile file, + @NotNull VcsRevisionNumber revision) { + myDiffProvider = diffProvider; + myFile = file; + myRevision = revision; + } + + @NotNull + @Override + public VcsRevisionNumber getRevisionNumber() { + return myRevision; + } + + @Nullable + @Override + public String loadContent() { + ContentRevision contentRevision = myDiffProvider.createFileContent(myRevision, myFile); + if (contentRevision == null) return null; + return loadContentRevision(contentRevision); + } + } + + @Nullable + private static String loadContentRevision(@NotNull ContentRevision contentRevision) { + try { + if (contentRevision instanceof ByteBackedContentRevision) { + byte[] revisionContent = ((ByteBackedContentRevision)contentRevision).getContentAsBytes(); + FilePath filePath = contentRevision.getFile(); + + if (revisionContent != null) { + Charset charset = DiffContentFactoryImpl.guessCharset(revisionContent, filePath); + return CharsetToolkit.decodeString(revisionContent, charset); } else { - return myContentRevision.getContent(); + return null; } } - catch (VcsException ex) { - return null; + else { + return contentRevision.getContent(); } } + catch (VcsException ex) { + return null; + } } } diff --git a/platform/vcs-log/impl/src/META-INF/vcs-log.xml b/platform/vcs-log/impl/src/META-INF/vcs-log.xml index 3d6df26e6762..d935605aea2b 100644 --- a/platform/vcs-log/impl/src/META-INF/vcs-log.xml +++ b/platform/vcs-log/impl/src/META-INF/vcs-log.xml @@ -30,7 +30,7 @@ - + diff --git a/platform/vcs-tests/src/com/intellij/openapi/vcs/TestVcsNotifier.java b/platform/vcs-tests/src/com/intellij/openapi/vcs/TestVcsNotifier.java index 2f16552ef0d3..a2f51131b051 100644 --- a/platform/vcs-tests/src/com/intellij/openapi/vcs/TestVcsNotifier.java +++ b/platform/vcs-tests/src/com/intellij/openapi/vcs/TestVcsNotifier.java @@ -41,6 +41,11 @@ public class TestVcsNotifier extends VcsNotifier { return notification; } + @NotNull + public List getNotifications(){ + return ContainerUtil.unmodifiableOrEmptyList(myNotifications); + } + public void cleanup() { myNotifications.clear(); } diff --git a/platform/xdebugger-impl/intellij.platform.debugger.impl.iml b/platform/xdebugger-impl/intellij.platform.debugger.impl.iml index 1a47d189939a..07dbdba41cbb 100644 --- a/platform/xdebugger-impl/intellij.platform.debugger.impl.iml +++ b/platform/xdebugger-impl/intellij.platform.debugger.impl.iml @@ -10,11 +10,10 @@ - - - + +
\ No newline at end of file diff --git a/platform/xdebugger-testFramework/intellij.platform.debugger.testFramework.iml b/platform/xdebugger-testFramework/intellij.platform.debugger.testFramework.iml new file mode 100644 index 000000000000..99d0862410e0 --- /dev/null +++ b/platform/xdebugger-testFramework/intellij.platform.debugger.testFramework.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java b/platform/xdebugger-testFramework/src/com/intellij/xdebugger/XDebuggerTestUtil.java similarity index 100% rename from platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java rename to platform/xdebugger-testFramework/src/com/intellij/xdebugger/XDebuggerTestUtil.java diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestCompositeNode.java b/platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestCompositeNode.java similarity index 100% rename from platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestCompositeNode.java rename to platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestCompositeNode.java diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestContainer.java b/platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestContainer.java similarity index 100% rename from platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestContainer.java rename to platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestContainer.java diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestEvaluationCallback.java b/platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestEvaluationCallback.java similarity index 100% rename from platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestEvaluationCallback.java rename to platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestEvaluationCallback.java diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestValueNode.java b/platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestValueNode.java similarity index 100% rename from platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestValueNode.java rename to platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestValueNode.java diff --git a/plugins/InspectionGadgets/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java b/plugins/InspectionGadgets/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java index 5774daa3828e..d929ca8b4333 100644 --- a/plugins/InspectionGadgets/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java +++ b/plugins/InspectionGadgets/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java @@ -18,7 +18,7 @@ import com.intellij.psi.util.*; import com.intellij.refactoring.util.RefactoringChangeUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.containers.ContainerUtil; +import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.ExpressionUtils; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -628,16 +628,13 @@ public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalI final PsiType denotableFunctionalInterfaceType = RefactoringChangeUtil.getTypeByExpression(lambda); if (denotableFunctionalInterfaceType == null) return lambda; - Collection comments = ContainerUtil.map(PsiTreeUtil.findChildrenOfType(lambda, PsiComment.class), - (comment) -> (PsiComment)comment.copy()); - final String methodRefText = createMethodReferenceText(body, functionalInterfaceType, lambda.getParameterList().getParameters()); if (methodRefText != null) { final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); final PsiExpression psiExpression = factory.createExpressionFromText(methodRefText, lambda); final SmartTypePointer typePointer = SmartTypePointerManager.getInstance(project).createSmartTypePointer(denotableFunctionalInterfaceType); - PsiExpression replace = (PsiExpression)lambda.replace(psiExpression); + PsiExpression replace = (PsiExpression)new CommentTracker().replaceAndRestoreComments(lambda, psiExpression); final PsiType functionalTypeAfterReplacement = GenericsUtil.getVariableTypeByExpressionType(((PsiMethodReferenceExpression)replace).getFunctionalInterfaceType()); functionalInterfaceType = typePointer.getType(); if (functionalInterfaceType != null && (functionalTypeAfterReplacement == null || @@ -652,7 +649,6 @@ public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalI replace = (PsiExpression)replace.replace(cast); } - AnonymousCanBeLambdaInspection.restoreComments(comments, replace); JavaCodeStyleManager.getInstance(project).shortenClassReferences(replace); return replace; } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/references/InjectedReferencesContributor.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/references/InjectedReferencesContributor.java index 066a191daa94..f5762bb740c1 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/references/InjectedReferencesContributor.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/references/InjectedReferencesContributor.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2014 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. - */ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.intellij.plugins.intelliLang.references; import com.intellij.lang.injection.InjectedLanguageManager; @@ -44,11 +30,6 @@ import java.util.List; */ public class InjectedReferencesContributor extends PsiReferenceContributor { private static final Key INJECTED_REFERENCES = Key.create("injected references"); - private final ReferenceInjector[] myExtensions; - - InjectedReferencesContributor() { - myExtensions = ReferenceInjector.EXTENSION_POINT_NAME.getExtensions(); - } public static boolean isInjected(@Nullable PsiReference reference) { return reference != null && reference.getElement().getUserData(INJECTED_REFERENCES) != null; @@ -62,6 +43,7 @@ public class InjectedReferencesContributor extends PsiReferenceContributor { @Override public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { + final List extensions = ReferenceInjector.EXTENSION_POINT_NAME.getExtensionList(); registrar.registerReferenceProvider(PlatformPatterns.psiElement(), new PsiReferenceProvider() { @NotNull @Override @@ -70,7 +52,7 @@ public class InjectedReferencesContributor extends PsiReferenceContributor { Project project = element.getProject(); Configuration configuration = Configuration.getProjectInstance(project); final Ref injected = new Ref<>(Boolean.FALSE); - for (ReferenceInjector injector : myExtensions) { + for (ReferenceInjector injector : extensions) { Collection injections = configuration.getInjectionsByLanguageId(injector.getId()); for (BaseInjection injection : injections) { if (injection.acceptForReference(element)) { diff --git a/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ssh/SmPublicKeyAuthentification.java b/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ssh/SmPublicKeyAuthentification.java index d232ef29b4a1..405f743ea79e 100644 --- a/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ssh/SmPublicKeyAuthentification.java +++ b/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ssh/SmPublicKeyAuthentification.java @@ -19,6 +19,6 @@ package com.intellij.cvsSupport2.connections.ssh; * author: lesya */ public interface SmPublicKeyAuthentification { - public Throwable PRIVATE_KEY_FILE = new Throwable(); - public Throwable PASSPHRASE = new Throwable(); + Throwable PRIVATE_KEY_FILE = new Throwable(); + Throwable PASSPHRASE = new Throwable(); } diff --git a/plugins/cvs/cvs-core/src/com/intellij/openapi/cvsIntegration/DateOrRevision.java b/plugins/cvs/cvs-core/src/com/intellij/openapi/cvsIntegration/DateOrRevision.java index 798261a74cbb..5b32a58f806d 100644 --- a/plugins/cvs/cvs-core/src/com/intellij/openapi/cvsIntegration/DateOrRevision.java +++ b/plugins/cvs/cvs-core/src/com/intellij/openapi/cvsIntegration/DateOrRevision.java @@ -17,8 +17,8 @@ package com.intellij.openapi.cvsIntegration; public interface DateOrRevision { - public String getBranch(); - public boolean shouldUseBranch(); - public String getDate(); - public boolean shouldUseDate(); + String getBranch(); + boolean shouldUseBranch(); + String getDate(); + boolean shouldUseDate(); } diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/CvsUtil.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/CvsUtil.java index 0e24b73a4b78..640748ddeaa1 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/CvsUtil.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/CvsUtil.java @@ -727,7 +727,7 @@ public class CvsUtil { return dirTag.startsWith(STICKY_BRANCH_TAG_PREFIX) || dirTag.startsWith(STICKY_NON_BRANCH_TAG_PREFIX); } - private static interface FileCondition { + private interface FileCondition { boolean verify(File file); } diff --git a/plugins/devkit/devkit-core/src/dom/generator/FileManager.java b/plugins/devkit/devkit-core/src/dom/generator/FileManager.java index 8ad5c711a6c4..b82843d7f769 100644 --- a/plugins/devkit/devkit-core/src/dom/generator/FileManager.java +++ b/plugins/devkit/devkit-core/src/dom/generator/FileManager.java @@ -28,6 +28,6 @@ import java.io.File; * @author Konstantin Bulenkov */ public interface FileManager { - public File releaseOutputFile(File outFile); - public File getOutputFile(File target); + File releaseOutputFile(File outFile); + File getOutputFile(File target); } diff --git a/plugins/generate-tostring/testSrc/org/jetbrains/java/generate/test/DummyTestBean.java b/plugins/generate-tostring/testSrc/org/jetbrains/java/generate/test/DummyTestBean.java index 9277963c06b4..cb09076b2447 100644 --- a/plugins/generate-tostring/testSrc/org/jetbrains/java/generate/test/DummyTestBean.java +++ b/plugins/generate-tostring/testSrc/org/jetbrains/java/generate/test/DummyTestBean.java @@ -27,7 +27,7 @@ public class DummyTestBean extends Config implements Serializable { public static final String CONST_FIELD = "XXX_XXX"; private static final String CONST_FIELD_PRIV = "XXX_XXX"; - private final transient String tran = "xxx"; + private static final transient String tran = "xxx"; // private static String myStaticString; // private String[] nameStrings = new String[] { "Claus", "Ibsen" }; diff --git a/plugins/git4idea/intellij.vcs.git.iml b/plugins/git4idea/intellij.vcs.git.iml index 116eac1deb0e..2452eedd41f5 100644 --- a/plugins/git4idea/intellij.vcs.git.iml +++ b/plugins/git4idea/intellij.vcs.git.iml @@ -26,10 +26,7 @@ - - - @@ -37,7 +34,6 @@ - diff --git a/plugins/git4idea/src/git4idea/commands/GitHandler.java b/plugins/git4idea/src/git4idea/commands/GitHandler.java index d862ae995f70..a8a6a6744be3 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandler.java @@ -536,7 +536,7 @@ public abstract class GitHandler { @Deprecated private final List myLastOutput = Collections.synchronizedList(new ArrayList<>()); @Deprecated - private final int LAST_OUTPUT_SIZE = 5; + private static final int LAST_OUTPUT_SIZE = 5; @Deprecated private boolean myProgressParameterAllowed = false; @Deprecated diff --git a/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java b/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java index 47e692476f87..a9f91201fcb2 100644 --- a/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java +++ b/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java @@ -90,6 +90,14 @@ public class GitVFSListener extends VcsVFSListener { @Override protected void executeAdd(@NotNull final List addedFiles, @NotNull final Map copiedFiles) { + executeAddWithoutIgnores(addedFiles, copiedFiles, + (notIgnoredAddedFiles, copiedFilesMap) -> originalExecuteAdd(notIgnoredAddedFiles, copiedFilesMap)); + } + + @Override + protected void executeAddWithoutIgnores(@NotNull List addedFiles, + @NotNull Map copyFromMap, + @NotNull ExecuteAddCallback executeAddCallback) { saveUnsavedVcsIgnoreFiles(); // Filter added files before further processing Map> sortedFiles; @@ -117,7 +125,7 @@ public class GitVFSListener extends VcsVFSListener { } addedFiles.retainAll(retainedFiles); - AppUIUtil.invokeLaterIfProjectAlive(myProject, () -> originalExecuteAdd(addedFiles, copiedFiles)); + AppUIUtil.invokeLaterIfProjectAlive(myProject, () -> executeAddCallback.executeAdd(addedFiles, copyFromMap)); } }); } diff --git a/plugins/git4idea/tests/git4idea/notification/GitExternalFileNotifierTest.kt b/plugins/git4idea/tests/git4idea/notification/GitExternalFileNotifierTest.kt new file mode 100644 index 000000000000..c8422343e8ae --- /dev/null +++ b/plugins/git4idea/tests/git4idea/notification/GitExternalFileNotifierTest.kt @@ -0,0 +1,56 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package git4idea.notification + +import com.intellij.openapi.vcs.VcsBundle +import com.intellij.openapi.vcs.VcsConfiguration +import com.intellij.openapi.vcs.VcsShowConfirmationOption +import com.intellij.testFramework.RunAll +import com.intellij.testFramework.vcs.AbstractVcsTestCase.setStandardConfirmation +import com.intellij.util.ThrowableRunnable +import git4idea.test.GitSingleRepoTest +import junit.framework.TestCase + +class GitExternalFileNotifierTest : GitSingleRepoTest() { + + override fun setUp() { + super.setUp() + + setStandardConfirmation(project, vcs.name, VcsConfiguration.StandardConfirmation.ADD, VcsShowConfirmationOption.Value.SHOW_CONFIRMATION) + projectRoot.children //ensure that all subsequent VFS events will be fired after new files added to projectRoot + } + + override fun tearDown() { + RunAll() + .append(ThrowableRunnable { + setStandardConfirmation(project, vcs.name, VcsConfiguration.StandardConfirmation.ADD, + VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY) + }) + .append(ThrowableRunnable { super.tearDown() }) + .run() + } + + fun `test notification after external files added`(){ + file("file1.txt").create() + file("file2.txt").create() + + refresh() + + assertNotificationByMessage(VcsBundle.message("external.files.add.notification.message", vcs.displayName)) + } + + fun `test notification after external files and project configuration files added`(){ + file("file1.txt").create() + file("file2.txt").create() + file("module.iml").create() + + refresh() + + assertSize(2, vcsNotifier.notifications) + assertNotificationByMessage(VcsBundle.message("external.files.add.notification.message", vcs.displayName)) + assertNotificationByMessage(VcsBundle.message("project.configuration.files.add.notification.message", vcs.displayName)) + } + + private fun assertNotificationByMessage(notificationContent: String) = + vcsNotifier.notifications.find { it.content == notificationContent } + ?: TestCase.fail("Notification $notificationContent not found") +} diff --git a/plugins/github/intellij.vcs.github.iml b/plugins/github/intellij.vcs.github.iml index 532846ee7438..4cdc90754f9f 100644 --- a/plugins/github/intellij.vcs.github.iml +++ b/plugins/github/intellij.vcs.github.iml @@ -31,7 +31,6 @@ -
\ No newline at end of file diff --git a/plugins/gradle/java/src/execution/build/GradleProjectTaskRunner.java b/plugins/gradle/java/src/execution/build/GradleProjectTaskRunner.java index 51b463983d84..8e1c48f893c4 100644 --- a/plugins/gradle/java/src/execution/build/GradleProjectTaskRunner.java +++ b/plugins/gradle/java/src/execution/build/GradleProjectTaskRunner.java @@ -266,7 +266,7 @@ public class GradleProjectTaskRunner extends ProjectTaskRunner { Collection buildRootTasks = buildTasksMap.getModifiable(rootProjectPath); final String moduleType = getExternalModuleType(module); - if (!moduleBuildTask.isIncrementalBuild()) { + if (!moduleBuildTask.isIncrementalBuild() && !(moduleBuildTask instanceof ModuleFilesBuildTask)) { projectInitScripts.add(String.format(FORCE_COMPILE_TASKS_INIT_SCRIPT_TEMPLATE, gradlePath)); } String assembleTask = "assemble"; diff --git a/plugins/gradle/plugin-resources/META-INF/plugin.xml b/plugins/gradle/plugin-resources/META-INF/plugin.xml index 8c937cb00d62..819d6e60d5d5 100644 --- a/plugins/gradle/plugin-resources/META-INF/plugin.xml +++ b/plugins/gradle/plugin-resources/META-INF/plugin.xml @@ -117,7 +117,7 @@ - + diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionHelper.java index b1b81730819c..85517ef367eb 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionHelper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionHelper.java @@ -5,6 +5,8 @@ import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.application.ex.ApplicationInfoEx; +import com.intellij.openapi.application.impl.ApplicationInfoImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.model.ExternalSystemException; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId; @@ -137,17 +139,21 @@ public class GradleExecutionHelper { } } + List filteredArgs = ContainerUtil.newArrayList(); if (!settings.getArguments().isEmpty()) { String loggableArgs = StringUtil.join(obfuscatePasswordParameters(settings.getArguments()), " "); LOG.info("Passing command-line args to Gradle Tooling API: " + loggableArgs); // filter nulls and empty strings - List filteredArgs = ContainerUtil.mapNotNull(settings.getArguments(), s -> StringUtil.isEmpty(s) ? null : s); + filteredArgs.addAll(ContainerUtil.mapNotNull(settings.getArguments(), s -> StringUtil.isEmpty(s) ? null : s)); // TODO remove this replacement when --tests option will become available for tooling API replaceTestCommandOptionWithInitScript(filteredArgs); - operation.withArguments(ArrayUtil.toStringArray(filteredArgs)); } + filteredArgs.add("-Didea.active=true"); + filteredArgs.add("-Didea.version=" + getIdeaVersion()); + operation.withArguments(ArrayUtil.toStringArray(filteredArgs)); + setupEnvironment(operation, settings, gradleVersion, id, listener); final String javaHome = settings.getJavaHome(); @@ -779,4 +785,9 @@ public class GradleExecutionHelper { settings.withArguments(commandLineArgs).withVmOptions(extraJvmArgs); prepare(operation, id, settings, listener, connection, standardOutput, standardError); } + + private static String getIdeaVersion() { + ApplicationInfoEx appInfo = ApplicationInfoImpl.getShadowInstance(); + return appInfo.getMajorVersion() + "." + appInfo.getMinorVersion(); + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java index aefa12ffce08..df96af0e272e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java @@ -198,7 +198,7 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver previewLightWeightToolingModels = ContainerUtil.set(ExternalProjectPreview.class, GradleBuild.class); @@ -792,9 +792,4 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver T getExtraProject(Class modelClazz); diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy index dd39b4b7cb69..c38c0c815e83 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy @@ -157,7 +157,8 @@ class ExternalProjectBuilderImpl implements ModelBuilderService { externalTask.QName = task.name externalTask.description = task.description externalTask.group = task.group ?: "other" - externalTask.test = task instanceof Test + def ext = task.getExtensions()?.extraProperties + externalTask.test = (task instanceof Test) || (ext?.has("idea.internal.test") && Boolean.valueOf(ext.get("idea.internal.test"))) externalTask.type = ProjectExtensionsDataBuilderImpl.getType(task) result.put(externalTask.name, externalTask) } diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/internal/init/init.gradle b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/internal/init/init.gradle index 9df08b2b7dc9..462d1ca2e75c 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/internal/init/init.gradle +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/internal/init/init.gradle @@ -3,7 +3,6 @@ import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.jetbrains.plugins.gradle.tooling.internal.ExtraModelBuilder import org.gradle.util.* -System.setProperty("idea.active", "true") initscript { dependencies { classpath files(${EXTENSIONS_JARS_PATH}) diff --git a/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java b/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java index 4fe123a99773..5e88c2edad25 100644 --- a/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java +++ b/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java @@ -175,9 +175,6 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { else if (t == LAMBDA_BLOCK) { r = lambda_block(b, 0); } - else if (t == LAMBDA_EXPRESSION) { - r = lambda_expression(b, 0); - } else if (t == LEFT_SHIFT_SIGN) { r = left_shift_sign(b, 0); } @@ -968,40 +965,39 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // spread_list_argument | named_argument | lambda_argument | expression (map_argument_label map_argument)? + // spread_list_argument | named_argument | expression (map_argument_label map_argument)? static boolean argument(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "argument")) return false; boolean r; Marker m = enter_section_(b); r = spread_list_argument(b, l + 1); if (!r) r = named_argument(b, l + 1); - if (!r) r = lambda_argument(b, l + 1); - if (!r) r = argument_3(b, l + 1); + if (!r) r = argument_2(b, l + 1); exit_section_(b, m, null, r); return r; } // expression (map_argument_label map_argument)? - private static boolean argument_3(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "argument_3")) return false; + private static boolean argument_2(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "argument_2")) return false; boolean r; Marker m = enter_section_(b); r = expression(b, l + 1, -1); - r = r && argument_3_1(b, l + 1); + r = r && argument_2_1(b, l + 1); exit_section_(b, m, null, r); return r; } // (map_argument_label map_argument)? - private static boolean argument_3_1(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "argument_3_1")) return false; - argument_3_1_0(b, l + 1); + private static boolean argument_2_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "argument_2_1")) return false; + argument_2_1_0(b, l + 1); return true; } // map_argument_label map_argument - private static boolean argument_3_1_0(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "argument_3_1_0")) return false; + private static boolean argument_2_1_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "argument_2_1_0")) return false; boolean r; Marker m = enter_section_(b); r = map_argument_label(b, l + 1); @@ -1370,14 +1366,14 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // (<> mb_nl) enhanced_expression_or_application + // (<> mb_nl) expression_or_application static boolean assignment_expression_rvalue(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "assignment_expression_rvalue")) return false; boolean r, p; Marker m = enter_section_(b, l, _NONE_); r = assignment_expression_rvalue_0(b, l + 1); p = r; // pin = 1 - r = r && enhanced_expression_or_application(b, l + 1); + r = r && expression_or_application(b, l + 1); exit_section_(b, l, m, r, p, null); return r || p; } @@ -3268,16 +3264,6 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return true; } - /* ********************************************************** */ - // lambda_expression | expression_or_application - static boolean enhanced_expression_or_application(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "enhanced_expression_or_application")) return false; - boolean r; - r = lambda_expression(b, l + 1); - if (!r) r = expression_or_application(b, l + 1); - return r; - } - /* ********************************************************** */ // '{' mb_nl enum_members '}' public static boolean enum_body(PsiBuilder b, int l) { @@ -4313,28 +4299,6 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r; } - /* ********************************************************** */ - // !<> lambda_expression - static boolean lambda_argument(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "lambda_argument")) return false; - boolean r; - Marker m = enter_section_(b); - r = lambda_argument_0(b, l + 1); - r = r && lambda_expression(b, l + 1); - exit_section_(b, m, null, r); - return r; - } - - // !<> - private static boolean lambda_argument_0(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "lambda_argument_0")) return false; - boolean r; - Marker m = enter_section_(b, l, _NOT_); - r = !isApplicationArguments(b, l + 1); - exit_section_(b, l, m, r, false, null); - return r; - } - /* ********************************************************** */ // '{' mb_nl block_levels '}' public static boolean lambda_block(PsiBuilder b, int l) { @@ -4383,22 +4347,11 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r; } - /* ********************************************************** */ - // lambda_expression_base | clear_variants_and_fail - public static boolean lambda_expression(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "lambda_expression")) return false; - boolean r; - Marker m = enter_section_(b, l, _NONE_, LAMBDA_EXPRESSION, ""); - r = lambda_expression_base(b, l + 1); - if (!r) r = clear_variants_and_fail(b, l + 1); - exit_section_(b, l, m, r, false, null); - return r; - } - /* ********************************************************** */ // lambda_expression_head mb_nl lambda_body static boolean lambda_expression_base(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "lambda_expression_base")) return false; + if (!nextTokenIs(b, T_LPAREN)) return false; boolean r, p; Marker m = enter_section_(b, l, _NONE_); r = lambda_expression_head(b, l + 1); @@ -4413,6 +4366,7 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { // lambda_parameter_list mb_nl '->' static boolean lambda_expression_head(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "lambda_expression_head")) return false; + if (!nextTokenIsFast(b, T_LPAREN)) return false; boolean r; Marker m = enter_section_(b); r = lambda_parameter_list(b, l + 1); @@ -4423,25 +4377,38 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // modifier_list mb_type_element var - public static boolean lambda_parameter(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "lambda_parameter")) return false; + // empty_parens | '(' <> ')' + public static boolean lambda_parameter_list(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "lambda_parameter_list")) return false; + if (!nextTokenIs(b, T_LPAREN)) return false; boolean r; - Marker m = enter_section_(b, l, _NONE_, PARAMETER, ""); - r = modifier_list(b, l + 1); - r = r && mb_type_element(b, l + 1); - r = r && var(b, l + 1); - exit_section_(b, l, m, r, false, null); + Marker m = enter_section_(b); + r = empty_parens(b, l + 1); + if (!r) r = lambda_parameter_list_1(b, l + 1); + exit_section_(b, m, PARAMETER_LIST, r); return r; } - /* ********************************************************** */ - // parenthesized_lambda_parameter_list | single_lambda_parameter_list - static boolean lambda_parameter_list(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "lambda_parameter_list")) return false; + // '(' <> ')' + private static boolean lambda_parameter_list_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "lambda_parameter_list_1")) return false; boolean r; - r = parenthesized_lambda_parameter_list(b, l + 1); - if (!r) r = single_lambda_parameter_list(b, l + 1); + Marker m = enter_section_(b); + r = consumeToken(b, T_LPAREN); + r = r && comma_list(b, l + 1, GroovyGeneratedParser::lambda_parameter_list_1_1_0); + r = r && consumeToken(b, T_RPAREN); + exit_section_(b, m, null, r); + return r; + } + + // mb_nl parse_parameter + private static boolean lambda_parameter_list_1_1_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "lambda_parameter_list_1_1_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = mb_nl(b, l + 1); + r = r && parse_parameter(b, l + 1); + exit_section_(b, m, null, r); return r; } @@ -4557,14 +4524,14 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // ['=' mb_nl enhanced_expression_or_application] + // ['=' mb_nl expression_or_application] static boolean mb_initializer(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "mb_initializer")) return false; mb_initializer_0(b, l + 1); return true; } - // '=' mb_nl enhanced_expression_or_application + // '=' mb_nl expression_or_application private static boolean mb_initializer_0(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "mb_initializer_0")) return false; boolean r, p; @@ -4572,7 +4539,7 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { r = consumeTokenFast(b, T_ASSIGN); p = r; // pin = 1 r = r && report_error_(b, mb_nl(b, l + 1)); - r = p && enhanced_expression_or_application(b, l + 1) && r; + r = p && expression_or_application(b, l + 1) && r; exit_section_(b, l, m, r, p, null); return r || p; } @@ -5586,71 +5553,6 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r || p; } - /* ********************************************************** */ - // parenthesized_lambda_expression_head mb_nl lambda_body - static boolean parenthesized_lambda_expression_base(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "parenthesized_lambda_expression_base")) return false; - if (!nextTokenIs(b, T_LPAREN)) return false; - boolean r, p; - Marker m = enter_section_(b, l, _NONE_); - r = parenthesized_lambda_expression_head(b, l + 1); - p = r; // pin = 1 - r = r && report_error_(b, mb_nl(b, l + 1)); - r = p && lambda_body(b, l + 1) && r; - exit_section_(b, l, m, r, p, null); - return r || p; - } - - /* ********************************************************** */ - // parenthesized_lambda_parameter_list mb_nl '->' - static boolean parenthesized_lambda_expression_head(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "parenthesized_lambda_expression_head")) return false; - if (!nextTokenIsFast(b, T_LPAREN)) return false; - boolean r; - Marker m = enter_section_(b); - r = parenthesized_lambda_parameter_list(b, l + 1); - r = r && mb_nl(b, l + 1); - r = r && consumeToken(b, T_ARROW); - exit_section_(b, m, null, r); - return r; - } - - /* ********************************************************** */ - // empty_parens | '(' <> ')' - public static boolean parenthesized_lambda_parameter_list(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "parenthesized_lambda_parameter_list")) return false; - if (!nextTokenIs(b, T_LPAREN)) return false; - boolean r; - Marker m = enter_section_(b); - r = empty_parens(b, l + 1); - if (!r) r = parenthesized_lambda_parameter_list_1(b, l + 1); - exit_section_(b, m, PARAMETER_LIST, r); - return r; - } - - // '(' <> ')' - private static boolean parenthesized_lambda_parameter_list_1(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "parenthesized_lambda_parameter_list_1")) return false; - boolean r; - Marker m = enter_section_(b); - r = consumeToken(b, T_LPAREN); - r = r && comma_list(b, l + 1, GroovyGeneratedParser::parenthesized_lambda_parameter_list_1_1_0); - r = r && consumeToken(b, T_RPAREN); - exit_section_(b, m, null, r); - return r; - } - - // mb_nl lambda_parameter - private static boolean parenthesized_lambda_parameter_list_1_1_0(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "parenthesized_lambda_parameter_list_1_1_0")) return false; - boolean r; - Marker m = enter_section_(b); - r = mb_nl(b, l + 1); - r = r && lambda_parameter(b, l + 1); - exit_section_(b, m, null, r); - return r; - } - /* ********************************************************** */ // <> // | <> @@ -6136,11 +6038,85 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // modifier_list IDENTIFIER - public static boolean single_lambda_parameter(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "single_lambda_parameter")) return false; + // <> expression_or_application + // | expression_or_application !<> + // | lazy_lambda_block + static boolean single_argument_lambda_body(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_body")) return false; boolean r; - Marker m = enter_section_(b, l, _NONE_, PARAMETER, ""); + Marker m = enter_section_(b); + r = single_argument_lambda_body_0(b, l + 1); + if (!r) r = single_argument_lambda_body_1(b, l + 1); + if (!r) r = lazy_lambda_block(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // <> expression_or_application + private static boolean single_argument_lambda_body_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_body_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = isParameterizedClosure(b, l + 1); + r = r && expression_or_application(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // expression_or_application !<> + private static boolean single_argument_lambda_body_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_body_1")) return false; + boolean r; + Marker m = enter_section_(b); + r = expression_or_application(b, l + 1); + r = r && single_argument_lambda_body_1_1(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // !<> + private static boolean single_argument_lambda_body_1_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_body_1_1")) return false; + boolean r; + Marker m = enter_section_(b, l, _NOT_); + r = !isParsedAsClosure(b, l + 1); + exit_section_(b, l, m, r, false, null); + return r; + } + + /* ********************************************************** */ + // single_argument_lambda_expression_head mb_nl single_argument_lambda_body + static boolean single_argument_lambda_expression_base(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_expression_base")) return false; + boolean r, p; + Marker m = enter_section_(b, l, _NONE_); + r = single_argument_lambda_expression_head(b, l + 1); + p = r; // pin = 1 + r = r && report_error_(b, mb_nl(b, l + 1)); + r = p && single_argument_lambda_body(b, l + 1) && r; + exit_section_(b, l, m, r, p, null); + return r || p; + } + + /* ********************************************************** */ + // single_argument_lambda_parameter_list mb_nl '->' + static boolean single_argument_lambda_expression_head(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_expression_head")) return false; + boolean r; + Marker m = enter_section_(b); + r = single_argument_lambda_parameter_list(b, l + 1); + r = r && mb_nl(b, l + 1); + r = r && consumeToken(b, T_ARROW); + exit_section_(b, m, null, r); + return r; + } + + /* ********************************************************** */ + // modifier_list IDENTIFIER + public static boolean single_argument_lambda_parameter(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_parameter")) return false; + boolean r; + Marker m = enter_section_(b, l, _NONE_, PARAMETER, ""); r = modifier_list(b, l + 1); r = r && consumeToken(b, IDENTIFIER); exit_section_(b, l, m, r, false, null); @@ -6148,12 +6124,23 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // single_lambda_parameter - public static boolean single_lambda_parameter_list(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "single_lambda_parameter_list")) return false; + // !<> single_argument_lambda_parameter + public static boolean single_argument_lambda_parameter_list(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_parameter_list")) return false; boolean r; - Marker m = enter_section_(b, l, _NONE_, PARAMETER_LIST, ""); - r = single_lambda_parameter(b, l + 1); + Marker m = enter_section_(b, l, _NONE_, PARAMETER_LIST, ""); + r = single_argument_lambda_parameter_list_0(b, l + 1); + r = r && single_argument_lambda_parameter(b, l + 1); + exit_section_(b, l, m, r, false, null); + return r; + } + + // !<> + private static boolean single_argument_lambda_parameter_list_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_parameter_list_0")) return false; + boolean r; + Marker m = enter_section_(b, l, _NOT_); + r = !isApplicationArguments(b, l + 1); exit_section_(b, l, m, r, false, null); return r; } @@ -7513,7 +7500,8 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { // 14: PREFIX(not_expression) ATOM(cast_expression) // 15: POSTFIX(index_expression) POSTFIX(safe_index_expression) POSTFIX(postfix_unary_expression) // 16: POSTFIX(method_reference_expression) POSTFIX(attribute_expression) POSTFIX(qualified_reference_expression) POSTFIX(property_expression) - // 17: POSTFIX(method_call_expression) ATOM(lazy_closure) ATOM(parenthesized_lambda_expression) ATOM(list_or_map) + // 17: POSTFIX(method_call_expression) ATOM(lazy_closure) ATOM(lambda_expression) ATOM(single_argument_lambda_expression) + // ATOM(list_or_map) // 18: ATOM(new_anonymous_expression) ATOM(new_expression) // 19: ATOM(unqualified_reference_expression) ATOM(built_in_type_expression) ATOM(literal) ATOM(gstring) // ATOM(regex) ATOM(parenthesized_expression) @@ -7527,7 +7515,8 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { if (!r) r = not_expression(b, l + 1); if (!r) r = cast_expression(b, l + 1); if (!r) r = lazy_closure(b, l + 1); - if (!r) r = parenthesized_lambda_expression(b, l + 1); + if (!r) r = lambda_expression(b, l + 1); + if (!r) r = single_argument_lambda_expression(b, l + 1); if (!r) r = list_or_map(b, l + 1); if (!r) r = new_anonymous_expression(b, l + 1); if (!r) r = new_expression(b, l + 1); @@ -8203,12 +8192,23 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r; } - // parenthesized_lambda_expression_base | clear_variants_and_fail - public static boolean parenthesized_lambda_expression(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "parenthesized_lambda_expression")) return false; + // lambda_expression_base | clear_variants_and_fail + public static boolean lambda_expression(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "lambda_expression")) return false; boolean r; - Marker m = enter_section_(b, l, _NONE_, LAMBDA_EXPRESSION, ""); - r = parenthesized_lambda_expression_base(b, l + 1); + Marker m = enter_section_(b, l, _NONE_, LAMBDA_EXPRESSION, ""); + r = lambda_expression_base(b, l + 1); + if (!r) r = clear_variants_and_fail(b, l + 1); + exit_section_(b, l, m, r, false, null); + return r; + } + + // single_argument_lambda_expression_base | clear_variants_and_fail + public static boolean single_argument_lambda_expression(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_expression")) return false; + boolean r; + Marker m = enter_section_(b, l, _NONE_, LAMBDA_EXPRESSION, ""); + r = single_argument_lambda_expression_base(b, l + 1); if (!r) r = clear_variants_and_fail(b, l + 1); exit_section_(b, l, m, r, false, null); return r; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf index d4b4db0f9983..9a6bd2a022d3 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf @@ -938,32 +938,28 @@ array_declaration ::= mandatory_expression optional_expression* { consumeTokenMe private mandatory_expression ::= '[' expression ']' { pin = 1 consumeTokenMethod = 'consumeTokenFast' } private optional_expression ::= '[' expression? ']' { pin = 1 consumeTokenMethod = 'consumeTokenFast' } -private priority1_2 ::= method_call_expression | lazy_closure | parenthesized_lambda_expression | list_or_map +private priority1_2 ::= method_call_expression | lazy_closure | lambda_expression | single_argument_lambda_expression | list_or_map constructor_call_expression ::= &('this' | 'super') unqualified_reference_expression call_tail method_call_expression ::= expression call_tail private call_tail ::= call_argument_list (mb_nl lazy_closure)* | empty_argument_list <> -lambda_expression ::= lambda_expression_base | clear_variants_and_fail +lambda_expression ::= lambda_expression_base | clear_variants_and_fail private lambda_expression_base ::= lambda_expression_head mb_nl lambda_body { pin = 1 } private lambda_expression_head ::= lambda_parameter_list mb_nl '->' { consumeTokenMethod = 'consumeTokenFast' } -private lambda_parameter_list ::= parenthesized_lambda_parameter_list | single_lambda_parameter_list +lambda_parameter_list ::= empty_parens | '(' <> ')' { elementType = parameter_list } +private lambda_body ::= (!<> lazy_lambda_block) | expression_or_application -parenthesized_lambda_expression ::= parenthesized_lambda_expression_base | clear_variants_and_fail { elementType = lambda_expression } -private parenthesized_lambda_expression_base ::= parenthesized_lambda_expression_head mb_nl lambda_body { pin = 1 } -private parenthesized_lambda_expression_head ::= parenthesized_lambda_parameter_list mb_nl '->' -{ - consumeTokenMethod = 'consumeTokenFast' -} +single_argument_lambda_expression::= single_argument_lambda_expression_base | clear_variants_and_fail { elementType = lambda_expression } +private single_argument_lambda_expression_base ::= single_argument_lambda_expression_head mb_nl single_argument_lambda_body { pin = 1 } +private single_argument_lambda_expression_head ::= single_argument_lambda_parameter_list mb_nl '->' { consumeTokenMethod = 'consumeTokenFast' } -parenthesized_lambda_parameter_list ::= empty_parens | '(' <> ')' { elementType = parameter_list } -lambda_parameter ::= modifier_list mb_type_element var { elementType = parameter } - -single_lambda_parameter_list ::= single_lambda_parameter { elementType = parameter_list } -single_lambda_parameter ::= modifier_list IDENTIFIER { +single_argument_lambda_parameter_list ::= !<> single_argument_lambda_parameter { elementType = parameter_list } +single_argument_lambda_parameter ::= modifier_list IDENTIFIER { elementType = parameter } - -private lambda_body ::= (!<> lazy_lambda_block) | expression_or_application +private single_argument_lambda_body ::= <> expression_or_application + | expression_or_application !<> + | lazy_lambda_block lazy_lambda_block ::= <> { elementType = lambda_block @@ -1103,7 +1099,7 @@ elvis_expression ::= expression mb_nl ('?:' mb_nl) expression private priority15 ::= assignment_expression | tuple_assignment_expression assignment_expression ::= expression assignment_expression_rvalue { rightAssociative = true } -private assignment_expression_rvalue ::= (<> mb_nl) enhanced_expression_or_application { pin = 1 } +private assignment_expression_rvalue ::= (<> mb_nl) expression_or_application { pin = 1 } tuple_assignment_expression ::= single_tuple_assignment | multi_tuple_assignment private single_tuple_assignment ::= single_tuple tuple_initializer // don't pin because "(foo)" may be a parenthesized expression @@ -1120,7 +1116,6 @@ tuple ::= '(' unqualified_reference_expression (',' unqualified_reference_expres // region Applications expression_or_application ::= <> { elementType = '' name = '' } -private enhanced_expression_or_application ::= lambda_expression | expression_or_application private expression_or_application_inner ::= expression application* private application ::= no_nl <> { @@ -1168,9 +1163,8 @@ application_argument_list ::= <> private application_arguments ::= argument (',' mb_nl argument)* private parse_argument ::= <> -private argument ::= spread_list_argument | named_argument | lambda_argument | expression (map_argument_label map_argument)? +private argument ::= spread_list_argument | named_argument | expression (map_argument_label map_argument)? -private lambda_argument ::= !<> lambda_expression left map_argument_label ::= &':' { elementType = argument_label @@ -1257,7 +1251,7 @@ left doc_reference_tail ::= '.' code_reference_part { elementType = code_referen // region Variables private var ::= IDENTIFIER mb_initializer -private mb_initializer ::= ['=' mb_nl enhanced_expression_or_application] +private mb_initializer ::= ['=' mb_nl expression_or_application] { pin('.*') = 1 consumeTokenMethod = 'consumeTokenFast' diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parserUtils.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parserUtils.kt index 932ae83f164d..117743b69048 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parserUtils.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parserUtils.kt @@ -18,7 +18,7 @@ import com.intellij.psi.tree.TokenSet import org.jetbrains.plugins.groovy.GroovyBundle import org.jetbrains.plugins.groovy.lang.lexer.GroovyLexer import org.jetbrains.plugins.groovy.lang.parser.GroovyGeneratedParser.closure_header_with_arrow -import org.jetbrains.plugins.groovy.lang.parser.GroovyGeneratedParser.parenthesized_lambda_expression_head +import org.jetbrains.plugins.groovy.lang.parser.GroovyGeneratedParser.lambda_expression_head import org.jetbrains.plugins.groovy.lang.psi.GroovyElementTypes.* import org.jetbrains.plugins.groovy.lang.psi.GroovyTokenSets.* import org.jetbrains.plugins.groovy.util.get @@ -417,6 +417,10 @@ private fun castOperandCheckInner(builder: PsiBuilder): Boolean { return false } +fun isParsedAsClosure(builder: PsiBuilder, level: Int): Boolean { + return builder.latestDoneMarker?.tokenType == CLOSURE +} + fun isParameterizedClosure(builder: PsiBuilder, level: Int): Boolean { return builder.lookahead { isParameterizedClosureInner(this, level) @@ -431,7 +435,7 @@ private fun isParameterizedClosureInner(builder: PsiBuilder, level: Int): Boolea fun isParameterizedLambda(builder: PsiBuilder, level: Int): Boolean { return builder.lookahead { - parenthesized_lambda_expression_head(builder, level) + lambda_expression_head(builder, level) } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrTypeParameter.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrTypeParameter.java index 13d820e3f66e..dd4fd39f505f 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrTypeParameter.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrTypeParameter.java @@ -24,6 +24,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini * @author ilyas */ public interface GrTypeParameter extends GrTypeDefinition, PsiTypeParameter { - public static final GrTypeParameter[] EMPTY_ARRAY = new GrTypeParameter[0]; + GrTypeParameter[] EMPTY_ARRAY = new GrTypeParameter[0]; ArrayFactory ARRAY_FACTORY = count -> count == 0 ? EMPTY_ARRAY : new GrTypeParameter[count]; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrDynamicImplicitElement.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrDynamicImplicitElement.java index 4cc754136aa4..134004b5e542 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrDynamicImplicitElement.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrDynamicImplicitElement.java @@ -29,12 +29,12 @@ import org.jetbrains.annotations.Nullable; */ public interface GrDynamicImplicitElement extends ItemPresentation, NavigationItem { @Nullable - public PsiClass getContainingClassElement(); + PsiClass getContainingClassElement(); @NotNull - public SearchScope getUseScope(); + SearchScope getUseScope(); - public PsiFile getContainingFile(); + PsiFile getContainingFile(); - public String getContainingClassName(); + String getContainingClassName(); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy index 3c372e044886..3b686c9777ea 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy @@ -794,6 +794,12 @@ class ExpressionsParsingTest extends GroovyParsingTestCase { void testlambda$assign4() { doTest() } + void testlambda$assign5() { doTest() } + + void testlambda$assign6() { doTest() } + + void testlambda$assign7() { doTest() } + void testlambda$methodCall1() { doTest() } void testlambda$methodCall2() { doTest() } @@ -818,6 +824,16 @@ class ExpressionsParsingTest extends GroovyParsingTestCase { void testlambda$methodCall12() { doTest() } + void testlambda$methodCall13() { doTest() } + + void testlambda$methodCall14() { doTest() } + + void testlambda$methodCall15() { doTest() } + + void testlambda$methodCall16() { doTest() } + + void testlambda$methodCall17() { doTest() } + void testlambda$command1() { doTest() } void testlambda$command2() { doTest() } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveLocalTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveLocalTest.groovy index e268592f0805..81e6fb16ac9b 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveLocalTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveLocalTest.groovy @@ -116,8 +116,8 @@ class ResolveLocalTest implements ResolveTest { void 'variable after lambda'() { resolveTest 'def l = a -> a; a ', null resolveTest 'def l = (a) -> a; a ', null - resolveTest 'def l = (Integer a) -> {} a ', null - resolveTest 'def l = a -> {} a ', null + resolveTest 'def l = (Integer a) -> {}; a ', null + resolveTest 'def l = a -> {}; a ', null } @Test diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign5.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign5.test new file mode 100644 index 000000000000..e72914d4265f --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign5.test @@ -0,0 +1,28 @@ +def l = ((a) -> a) +----- +Groovy script + Variable definitions + Modifiers + PsiElement(def)('def') + PsiWhiteSpace(' ') + Variable + PsiElement(identifier)('l') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Parenthesized expression + PsiElement(()('(') + Lambda expression + Parameter list + PsiElement(()('(') + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiElement())(')') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('a') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign6.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign6.test new file mode 100644 index 000000000000..bbff28f11932 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign6.test @@ -0,0 +1,26 @@ +def l = (a -> a) +----- +Groovy script + Variable definitions + Modifiers + PsiElement(def)('def') + PsiWhiteSpace(' ') + Variable + PsiElement(identifier)('l') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Parenthesized expression + PsiElement(()('(') + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('a') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign7.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign7.test new file mode 100644 index 000000000000..86b8e2e80100 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign7.test @@ -0,0 +1,108 @@ +def bar = (String a, Date b = null, int i = -1, String c, String d = 'd', String e, String ... f) -> {} +----- +Groovy script + Variable definitions + Modifiers + PsiElement(def)('def') + PsiWhiteSpace(' ') + Variable + PsiElement(identifier)('bar') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Lambda expression + Parameter list + PsiElement(()('(') + Parameter + Modifiers + + Type element + Reference element + PsiElement(identifier)('String') + PsiWhiteSpace(' ') + PsiElement(identifier)('a') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Parameter + Modifiers + + Type element + Reference element + PsiElement(identifier)('Date') + PsiWhiteSpace(' ') + PsiElement(identifier)('b') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Literal + PsiElement(null)('null') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Parameter + Modifiers + + Built in type + PsiElement(int)('int') + PsiWhiteSpace(' ') + PsiElement(identifier)('i') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Unary expression + PsiElement(-)('-') + Literal + PsiElement(Integer)('1') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Parameter + Modifiers + + Type element + Reference element + PsiElement(identifier)('String') + PsiWhiteSpace(' ') + PsiElement(identifier)('c') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Parameter + Modifiers + + Type element + Reference element + PsiElement(identifier)('String') + PsiWhiteSpace(' ') + PsiElement(identifier)('d') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Literal + PsiElement(single quoted string)(''d'') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Parameter + Modifiers + + Type element + Reference element + PsiElement(identifier)('String') + PsiWhiteSpace(' ') + PsiElement(identifier)('e') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Parameter + Modifiers + + Type element + Reference element + PsiElement(identifier)('String') + PsiWhiteSpace(' ') + PsiElement(...)('...') + PsiWhiteSpace(' ') + PsiElement(identifier)('f') + PsiElement())(')') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Lambda body block + PsiElement({)('{') + PsiElement(})('}') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/implicitReturn1.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/implicitReturn1.test index 12b4c6d6ed89..69ea5beddccc 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/implicitReturn1.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/implicitReturn1.test @@ -17,13 +17,16 @@ Groovy script Open block PsiElement({)('{') PsiWhiteSpace('\n ') - Reference expression - PsiElement(identifier)('a') - PsiWhiteSpace(' ') - PsiErrorElement:'->' unexpected + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiWhiteSpace(' ') PsiElement(->)('->') - PsiWhiteSpace(' ') - Reference expression - PsiElement(identifier)('a') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('a') PsiElement(new line)('\n') PsiElement(})('}') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall13.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall13.test new file mode 100644 index 000000000000..4ca9a50490ef --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall13.test @@ -0,0 +1,26 @@ +m(() -> {} as Foo) +----- +Groovy script + Method call + Reference expression + PsiElement(identifier)('m') + Arguments + PsiElement(()('(') + Safe cast expression + Lambda expression + Parameter list + PsiElement(()('(') + PsiElement())(')') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Lambda body block + PsiElement({)('{') + PsiElement(})('}') + PsiWhiteSpace(' ') + PsiElement(as)('as') + PsiWhiteSpace(' ') + Type element + Reference element + PsiElement(identifier)('Foo') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall14.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall14.test new file mode 100644 index 000000000000..1d2d411f0de3 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall14.test @@ -0,0 +1,29 @@ +m((() -> {}) as Foo) +----- +Groovy script + Method call + Reference expression + PsiElement(identifier)('m') + Arguments + PsiElement(()('(') + Safe cast expression + Parenthesized expression + PsiElement(()('(') + Lambda expression + Parameter list + PsiElement(()('(') + PsiElement())(')') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Lambda body block + PsiElement({)('{') + PsiElement(})('}') + PsiElement())(')') + PsiWhiteSpace(' ') + PsiElement(as)('as') + PsiWhiteSpace(' ') + Type element + Reference element + PsiElement(identifier)('Foo') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall15.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall15.test new file mode 100644 index 000000000000..cb070621bbd2 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall15.test @@ -0,0 +1,22 @@ +m((() -> {})) +----- +Groovy script + Method call + Reference expression + PsiElement(identifier)('m') + Arguments + PsiElement(()('(') + Parenthesized expression + PsiElement(()('(') + Lambda expression + Parameter list + PsiElement(()('(') + PsiElement())(')') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Lambda body block + PsiElement({)('{') + PsiElement(})('}') + PsiElement())(')') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall16.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall16.test new file mode 100644 index 000000000000..fb9fb7feb67f --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall16.test @@ -0,0 +1,24 @@ +m((a -> {})) +----- +Groovy script + Method call + Reference expression + PsiElement(identifier)('m') + Arguments + PsiElement(()('(') + Parenthesized expression + PsiElement(()('(') + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Lambda body block + PsiElement({)('{') + PsiElement(})('}') + PsiElement())(')') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall17.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall17.test new file mode 100644 index 000000000000..4546184f6467 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall17.test @@ -0,0 +1,30 @@ +m(a -> {} as Foo) +----- +Groovy script + Method call + Reference expression + PsiElement(identifier)('m') + Arguments + PsiElement(()('(') + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Safe cast expression + Closable block + PsiElement({)('{') + Parameter list + + PsiElement(})('}') + PsiWhiteSpace(' ') + PsiElement(as)('as') + PsiWhiteSpace(' ') + Type element + Reference element + PsiElement(identifier)('Foo') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/nestedLambda.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/nestedLambda.test index 9432a630aa4e..ce484d47ef6c 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/nestedLambda.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/nestedLambda.test @@ -19,11 +19,14 @@ Groovy script PsiWhiteSpace(' ') PsiElement(->)('->') PsiWhiteSpace(' ') - Reference expression - PsiElement(identifier)('b') - PsiWhiteSpace(' ') - PsiErrorElement:',' expected, got '->' - PsiElement(->)('->') - PsiWhiteSpace(' ') - Reference expression - PsiElement(identifier)('b') \ No newline at end of file + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('b') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('b') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/return1.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/return1.test index be22a273f657..a43670396055 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/return1.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/return1.test @@ -20,13 +20,16 @@ Groovy script RETURN statement PsiElement(return)('return') PsiWhiteSpace(' ') - Reference expression - PsiElement(identifier)('a') - PsiWhiteSpace(' ') - PsiErrorElement:'->' unexpected - PsiElement(->)('->') - PsiWhiteSpace(' ') - Reference expression - PsiElement(identifier)('a') + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('a') PsiElement(new line)('\n') PsiElement(})('}') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone1.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone1.test index 4284f8bb28ee..cd762db3d2da 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone1.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone1.test @@ -1,11 +1,14 @@ a -> a ----- Groovy script - Reference expression - PsiElement(identifier)('a') - PsiWhiteSpace(' ') - PsiErrorElement:'->' unexpected + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiWhiteSpace(' ') PsiElement(->)('->') - PsiWhiteSpace(' ') - Reference expression - PsiElement(identifier)('a') \ No newline at end of file + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('a') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone2.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone2.test index 4de12019daf3..ddd4a76eebac 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone2.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone2.test @@ -1,18 +1,19 @@ a -> { a } ----- Groovy script - Reference expression - PsiElement(identifier)('a') - PsiWhiteSpace(' ') - PsiErrorElement:'->' unexpected - PsiElement(->)('->') - PsiWhiteSpace(' ') - Closable block - PsiElement({)('{') - PsiWhiteSpace(' ') + Lambda expression Parameter list - - Reference expression - PsiElement(identifier)('a') + Parameter + Modifiers + + PsiElement(identifier)('a') PsiWhiteSpace(' ') - PsiElement(})('}') \ No newline at end of file + PsiElement(->)('->') + PsiWhiteSpace(' ') + Lambda body block + PsiElement({)('{') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('a') + PsiWhiteSpace(' ') + PsiElement(})('}') \ No newline at end of file diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java index dc6622a53445..2ee65e67b0bd 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java @@ -67,6 +67,14 @@ public class HgVFSListener extends VcsVFSListener { @Override protected void executeAdd(@NotNull final List addedFiles, @NotNull final Map copyFromMap) { + executeAddWithoutIgnores(addedFiles, copyFromMap, + (notIgnoredAddedFiles, copiedFilesMap) -> originalExecuteAdd(notIgnoredAddedFiles, copiedFilesMap)); + } + + @Override + protected void executeAddWithoutIgnores(@NotNull List addedFiles, + @NotNull Map copyFromMap, + @NotNull ExecuteAddCallback executeAddCallback) { saveUnsavedVcsIgnoreFiles(); // if a file is copied from another repository, then 'hg add' should be used instead of 'hg copy'. // Thus here we remove such files from the copyFromMap. @@ -104,7 +112,7 @@ public class HgVFSListener extends VcsVFSListener { // select files to add if there is something to select if (!addedFiles.isEmpty() || !copyFromMap.isEmpty()) { - AppUIUtil.invokeLaterIfProjectAlive(myProject, () -> originalExecuteAdd(addedFiles, copyFromMap)); + AppUIUtil.invokeLaterIfProjectAlive(myProject, () -> executeAddCallback.executeAdd(addedFiles, copyFromMap)); } } }.queue(); @@ -151,10 +159,6 @@ public class HgVFSListener extends VcsVFSListener { // separate adds from copies for (VirtualFile file : addedFiles) { - if (file.isDirectory()) { - continue; - } - final VirtualFile copyFrom = copyFromMap.get(file); if (copyFrom != null) { copies.put(copyFrom, file); @@ -176,7 +180,12 @@ public class HgVFSListener extends VcsVFSListener { } for (VirtualFile file : addedFiles) { - dirtyScopeManager.fileDirty(file); + if (file.isDirectory()) { + dirtyScopeManager.dirDirtyRecursively(file); + } + else { + dirtyScopeManager.fileDirty(file); + } } } }).queue(); diff --git a/plugins/maven/maven3-server-common/intellij.maven.server.m3.common.iml b/plugins/maven/maven3-server-common/intellij.maven.server.m3.common.iml index ab719393f7cf..f8537e3cc3e7 100644 --- a/plugins/maven/maven3-server-common/intellij.maven.server.m3.common.iml +++ b/plugins/maven/maven3-server-common/intellij.maven.server.m3.common.iml @@ -12,7 +12,12 @@ - + + + + + + @@ -22,7 +27,19 @@ - + + + + + + + + + + + + + @@ -32,7 +49,11 @@ - + + + + + diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index 7b879375074f..0ef2e872f248 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -196,7 +196,7 @@ - + diff --git a/plugins/svn4idea/intellij.vcs.svn.iml b/plugins/svn4idea/intellij.vcs.svn.iml index 6b41f80a9095..da2cc4a34896 100644 --- a/plugins/svn4idea/intellij.vcs.svn.iml +++ b/plugins/svn4idea/intellij.vcs.svn.iml @@ -10,15 +10,11 @@ - - - - diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java index fb92ec4d9165..56bbdfb7ca12 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java @@ -43,8 +43,8 @@ public class SvnNativeClientAuthTest extends SvnTestCase { private boolean mySaveCredentials = false; private boolean myCancelAuth = false; - private final String outHttpUser = "test"; - private final String outHttpPassword = "test"; + private static final String outHttpUser = "test"; + private static final String outHttpPassword = "test"; private final static Url ourHTTP_URL = parseUrl("http://svnsrvtest/stuff/autoTest", false); private final static Url ourHTTPS_URL = parseUrl("https://svnsrvtest:443/TestSSL/autoTest", false); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/model/TrelloCommentAction.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/model/TrelloCommentAction.java index f5d13b07f378..d5c8f7fa3536 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/model/TrelloCommentAction.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/model/TrelloCommentAction.java @@ -32,7 +32,7 @@ public class TrelloCommentAction extends Comment { private static class Data { - private final String text = ""; + private static final String text = ""; private TrelloBoard board; private TrelloCard card; } diff --git a/plugins/terminal/resources/.zshrc b/plugins/terminal/resources/.zshrc index adbc7f7bc754..7829d450d948 100644 --- a/plugins/terminal/resources/.zshrc +++ b/plugins/terminal/resources/.zshrc @@ -47,15 +47,13 @@ then fi function override_jb_variables { - env | while read VARIABLE + env | while IFS="=" read NAME VALUE do - NAME=${VARIABLE%%=*} if [[ $NAME = '_INTELLIJ_FORCE_SET_'* ]] then NEW_NAME=${NAME:20} if [ -n "$NEW_NAME" ] then - VALUE=${VARIABLE#*=} export "$NEW_NAME"="$VALUE" fi fi diff --git a/plugins/terminal/resources/META-INF/terminal.xml b/plugins/terminal/resources/META-INF/terminal.xml index ab7092da6734..f0971eda127b 100644 --- a/plugins/terminal/resources/META-INF/terminal.xml +++ b/plugins/terminal/resources/META-INF/terminal.xml @@ -15,7 +15,7 @@ - + diff --git a/plugins/terminal/resources/jediterm-bash.in b/plugins/terminal/resources/jediterm-bash.in index 78eacb5b3b86..e8cb2c66dfaf 100644 --- a/plugins/terminal/resources/jediterm-bash.in +++ b/plugins/terminal/resources/jediterm-bash.in @@ -32,15 +32,13 @@ function load_interactive_configs { } function override_jb_variables { - env | while read VARIABLE + env | while IFS="=" read NAME VALUE do - NAME=${VARIABLE%%=*} if [[ $NAME = '_INTELLIJ_FORCE_SET_'* ]] then NEW_NAME=${NAME:20} if [ -n "$NEW_NAME" ] then - VALUE=${VARIABLE#*=} export "$NEW_NAME"="$VALUE" fi fi diff --git a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java index 0c537bc7bde1..4cc757854c31 100644 --- a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java +++ b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java @@ -130,7 +130,7 @@ public class XsltHighlightingTest extends TestBase { final Project project = myFixture.getProject(); PsiDocumentManager.getInstance(project).commitAllDocuments(); - return TimeoutUtil.runAndGetExecutionTime(() -> ReadAction.run( + return TimeoutUtil.measureExecutionTime(() -> ReadAction.run( () -> CodeInsightTestFixtureImpl.instantiateAndRun(myFixture.getFile(), myFixture.getEditor(), ArrayUtil.EMPTY_INT_ARRAY, false))); } diff --git a/plugins/xslt-debugger/engine/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebugger.java b/plugins/xslt-debugger/engine/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebugger.java index 510d24e5cbdf..255742575a01 100644 --- a/plugins/xslt-debugger/engine/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebugger.java +++ b/plugins/xslt-debugger/engine/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebugger.java @@ -83,7 +83,7 @@ public interface RemoteDebugger extends Remote { String getInstruction() throws RemoteException; } - public interface Variable extends Remote { + interface Variable extends Remote { boolean isGlobal() throws RemoteException; Debugger.Variable.Kind getKind() throws RemoteException; diff --git a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlGenericValueAdapter.java b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlGenericValueAdapter.java index d7b13c413833..cfb8341e4e23 100644 --- a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlGenericValueAdapter.java +++ b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlGenericValueAdapter.java @@ -145,7 +145,7 @@ public class YamlGenericValueAdapter implements JsonValueAdapter { private static boolean isFloat(@NotNull String s) { if (INFS.contains(trimSign(s)) || NANS.contains(s)) return true; if (hasTag(s, "float")) return true; - return Pattern.matches("[-+]?[1-9](\\.[0-9]*[1-9])?([eE][-+]?[1-9][0-9]*)?", s); + return Pattern.matches("[-+]?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?", s); } @NotNull diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaHighlightingTest.java b/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaHighlightingTest.java index 3c47234d86d0..5f5a11693743 100644 --- a/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaHighlightingTest.java +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaHighlightingTest.java @@ -796,10 +796,17 @@ public class YamlByJsonSchemaHighlightingTest extends JsonSchemaHighlightingTest public void testTravisPythonVersion() throws Exception { @Language("JSON") String schema = FileUtil.loadFile(new File(getTestDataPath() + "/travis.schema.json")); doTest(schema, "python: 3.5"); // validates as 'number' - doTest(schema, "python: 3.50"); // validates as 'string' + doTest(schema, "python: 3.50"); // validates as 'number' + doTest(schema, "python: 3.50a"); // validates as 'string' doTest(schema, "python: null"); } + public void testTravisNode() throws Exception { + @Language("JSON") String schema = FileUtil.loadFile(new File(getTestDataPath() + "/travis.schema.json")); + doTest(schema, "node_js: \n" + + " - 2.10"); + } + public void testExpNumberNotation() throws Exception { doTest("{\n" + " \"properties\": {\n" + diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java index 3ba4e1cd96de..293f71dc5363 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java @@ -10,8 +10,8 @@ package com.jetbrains.python.debugger.pydev; */ public interface PyVariableLocator { - public String getThreadId(); + String getThreadId(); - public String getPyDBLocation(); + String getPyDBLocation(); } diff --git a/python/src/com/jetbrains/python/documentation/docstrings/NumpyDocStringBuilder.java b/python/src/com/jetbrains/python/documentation/docstrings/NumpyDocStringBuilder.java index db89d46fce9c..7b9496dd80a5 100644 --- a/python/src/com/jetbrains/python/documentation/docstrings/NumpyDocStringBuilder.java +++ b/python/src/com/jetbrains/python/documentation/docstrings/NumpyDocStringBuilder.java @@ -28,7 +28,7 @@ public class NumpyDocStringBuilder extends SectionBasedDocStringBuilder { public static final String DEFAULT_CONTINUATION_INDENT = PyIndentUtil.FOUR_SPACES; public static final char DEFAULT_SECTION_TITLE_UNDERLINE_SYMBOL = '-'; - private final char myUnderlineSymbol = DEFAULT_SECTION_TITLE_UNDERLINE_SYMBOL; + private static final char myUnderlineSymbol = DEFAULT_SECTION_TITLE_UNDERLINE_SYMBOL; public NumpyDocStringBuilder() { // Sections are not indented and continuation indent of 4 spaces like in Numpy sources diff --git a/python/src/com/jetbrains/python/run/RunnableScriptFilter.java b/python/src/com/jetbrains/python/run/RunnableScriptFilter.java index 6f81eba3158e..0f48516ed083 100644 --- a/python/src/com/jetbrains/python/run/RunnableScriptFilter.java +++ b/python/src/com/jetbrains/python/run/RunnableScriptFilter.java @@ -38,7 +38,7 @@ public interface RunnableScriptFilter { boolean isRunnableScript(PsiFile script, @NotNull Module module, Location location, @Nullable TypeEvalContext context); - public static boolean isIfNameMain(Location location) { + static boolean isIfNameMain(Location location) { PsiElement element = location.getPsiElement(); while (true) { final PyIfStatement ifStatement = PsiTreeUtil.getParentOfType(element, PyIfStatement.class); diff --git a/python/src/com/jetbrains/python/testing/pytestLegacy/PyTestRunConfigurationParams.java b/python/src/com/jetbrains/python/testing/pytestLegacy/PyTestRunConfigurationParams.java index 6f40141b0cb9..ce9864308263 100644 --- a/python/src/com/jetbrains/python/testing/pytestLegacy/PyTestRunConfigurationParams.java +++ b/python/src/com/jetbrains/python/testing/pytestLegacy/PyTestRunConfigurationParams.java @@ -19,8 +19,8 @@ package com.jetbrains.python.testing.pytestLegacy; * User : catherine */ public interface PyTestRunConfigurationParams { - public boolean useParam(); - public void useParam(boolean useParam); - public boolean useKeyword(); - public void useKeyword(boolean useKeyword); + boolean useParam(); + void useParam(boolean useParam); + boolean useKeyword(); + void useKeyword(boolean useKeyword); } diff --git a/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java b/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java index 06012a884f1a..447a312495ac 100644 --- a/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java +++ b/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java @@ -75,7 +75,7 @@ import java.util.List; public abstract class PyUnitTestTask extends PyExecutionFixtureTestTask { protected ProcessHandler myProcessHandler; - private final boolean shouldPrintOutput = false; + private static final boolean shouldPrintOutput = false; /** * Test root node */ diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyCodeFragmentTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyCodeFragmentTest.java index f8cfc7969037..beb5682bffbf 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyCodeFragmentTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyCodeFragmentTest.java @@ -40,9 +40,9 @@ public class PyCodeFragmentTest extends LightMarkedTestCase { return PythonTestUtil.getTestDataPath() + "/codeInsight/codefragment/"; } - final private String BEGIN_MARKER = ""; - final private String END_MARKER = ""; - final private String RESULT_MARKER = ""; + static final private String BEGIN_MARKER = ""; + static final private String END_MARKER = ""; + static final private String RESULT_MARKER = ""; private void doTest(Pair... files2Create) throws Exception { final String testName = getTestName(false).toLowerCase(); diff --git a/python/testSrc/intellij.python.community.tests.iml b/python/testSrc/intellij.python.community.tests.iml index 8c6872662cd6..3d4533f4976f 100644 --- a/python/testSrc/intellij.python.community.tests.iml +++ b/python/testSrc/intellij.python.community.tests.iml @@ -28,5 +28,6 @@ +
\ No newline at end of file diff --git a/resources/src/idea/JavaActions.xml b/resources/src/idea/JavaActions.xml index 01717a7e65a6..5deff17095d2 100644 --- a/resources/src/idea/JavaActions.xml +++ b/resources/src/idea/JavaActions.xml @@ -226,7 +226,8 @@ - + diff --git a/resources/src/idea/RichPlatformActions.xml b/resources/src/idea/RichPlatformActions.xml index 5bff857de91c..d350b3c18185 100644 --- a/resources/src/idea/RichPlatformActions.xml +++ b/resources/src/idea/RichPlatformActions.xml @@ -172,6 +172,11 @@ + + + + diff --git a/xml/dom-tests/tests/com/intellij/util/xml/DomExtensionsTest.java b/xml/dom-tests/tests/com/intellij/util/xml/DomExtensionsTest.java index e68e16b0278f..b8a577b06820 100644 --- a/xml/dom-tests/tests/com/intellij/util/xml/DomExtensionsTest.java +++ b/xml/dom-tests/tests/com/intellij/util/xml/DomExtensionsTest.java @@ -295,6 +295,6 @@ public class DomExtensionsTest extends DomTestCase { public MyStringBufferConverter(boolean b) { } } - public static interface MyAttribute extends GenericAttributeValue {} + public interface MyAttribute extends GenericAttributeValue {} } diff --git a/xml/dom-tests/tests/com/intellij/util/xml/DomSimpleValuesTest.java b/xml/dom-tests/tests/com/intellij/util/xml/DomSimpleValuesTest.java index 79ae28680b23..4c4650648e3f 100644 --- a/xml/dom-tests/tests/com/intellij/util/xml/DomSimpleValuesTest.java +++ b/xml/dom-tests/tests/com/intellij/util/xml/DomSimpleValuesTest.java @@ -15,7 +15,6 @@ */ package com.intellij.util.xml; -import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; @@ -532,7 +531,7 @@ public class DomSimpleValuesTest extends DomTestCase { public interface CmpField extends JavaeeDomModelElement { @NameValue - public GenericDomValue getName(); + GenericDomValue getName(); } public static class MyConverter extends Converter { diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java index 0919dccb25fe..6925fda73e5a 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java @@ -23,7 +23,7 @@ import org.jetbrains.annotations.NotNull; /** * @author cdr */ -public class XmlEncodingReference extends EncodingReference implements EmptyResolveMessageProvider, Comparable { +public class XmlEncodingReference extends EncodingReference implements EmptyResolveMessageProvider { private final int myPriority; public XmlEncodingReference(XmlAttributeValue value, final String charsetName, final TextRange rangeInElement, int priority) { @@ -31,7 +31,6 @@ public class XmlEncodingReference extends EncodingReference implements EmptyReso myPriority = priority; } - @Override public int compareTo(@NotNull XmlEncodingReference ref) { return myPriority - ref.myPriority; } diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/FollowFileHint.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/FollowFileHint.java index 3ea00daf9f69..e0cafccf71ad 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/FollowFileHint.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/FollowFileHint.java @@ -22,5 +22,5 @@ import org.intellij.plugins.relaxNG.compact.psi.RncFile; public interface FollowFileHint { Key KEY = Key.create("FollowFileHint"); - public boolean doFollow(RncFile file); + boolean doFollow(RncFile file); } diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/CommonElement.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/CommonElement.java index 095b66165396..6ae76e41b2fe 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/CommonElement.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/CommonElement.java @@ -27,7 +27,7 @@ public interface CommonElement { @Nullable E getPsiElement(); - static abstract class Visitor { + abstract class Visitor { public void visitElement(CommonElement pattern) { } diff --git a/xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java b/xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java index 61df0b54b68c..769b832e5e52 100644 --- a/xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java +++ b/xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java @@ -15,7 +15,7 @@ import org.jetbrains.annotations.Nullable; storages = @Storage("editor.xml") ) public class WebEditorOptions implements PersistentStateComponent { - private final boolean myShowCssColorPreviewInGutter = true; + private static final boolean myShowCssColorPreviewInGutter = true; private boolean mySelectWholeCssIdentifierOnDoubleClick = true; private boolean myShowCssInlineColorPreview = false; private boolean myAutomaticallyInsertClosingTag = true;