From ca6a5febe21d38ae67852a8ed78dd54281a7755c Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 11 Feb 2016 12:03:25 +0300 Subject: [PATCH 01/84] inspection toolwindow redesign base --- .../codeInspection/reference/RefEntity.java | 1 + .../ui/BatchProblemDescriptor.java | 129 +++++ .../intellij/codeInspection/ui/Browser.java | 532 ------------------ .../codeInspection/ui/InspectionNode.java | 17 +- .../codeInspection/ui/InspectionNodeInfo.java | 103 ++++ .../ui/InspectionResultsView.java | 139 +++-- .../codeInspection/ui/InspectionTree.java | 2 +- .../codeInspection/ui/InspectionTreeNode.java | 7 +- .../ui/ProblemDescriptionNode.java | 5 +- .../codeInspection/ui/QuickFixToolbar.java | 170 ++++++ .../codeInspection/ui/RefElementNode.java | 5 - .../usages/impl/UsagePreviewPanel.java | 39 +- 12 files changed, 520 insertions(+), 629 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java delete mode 100644 platform/lang-impl/src/com/intellij/codeInspection/ui/Browser.java create mode 100644 platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java create mode 100644 platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java diff --git a/platform/analysis-api/src/com/intellij/codeInspection/reference/RefEntity.java b/platform/analysis-api/src/com/intellij/codeInspection/reference/RefEntity.java index 3c7d66018e1b..fab170c4cae7 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/reference/RefEntity.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/reference/RefEntity.java @@ -48,6 +48,7 @@ public interface RefEntity extends UserDataHolder { * * @return the list of children. */ + @Nullable List getChildren(); /** diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java new file mode 100644 index 000000000000..6ee0c81c9e1a --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java @@ -0,0 +1,129 @@ +/* + * 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. + */ +package com.intellij.codeInspection.ui; + +import com.intellij.codeInspection.CommonProblemDescriptor; +import com.intellij.codeInspection.ProblemDescriptorBase; +import com.intellij.codeInspection.QuickFix; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * @author Dmitry Batkovich + */ +public class BatchProblemDescriptor { + private final static Logger LOG = Logger.getInstance(BatchProblemDescriptor.class); + + private MultiMap myMap = null; + private final List myDescriptors = new ArrayList<>(); + private final boolean myOnlyCount; + + public BatchProblemDescriptor(boolean count) { + myOnlyCount = count; + } + + public void addProblem(@Nullable CommonProblemDescriptor descriptor) { + myDescriptors.add(descriptor); + if (myOnlyCount) { + return; + } + if (isIntersectionTrivial()) { + return; + } + final boolean exist; + if (myMap == null) { + myMap = new MultiMap<>(); + exist = false; + } + else { + exist = true; + } + if (descriptor == null) { + myMap.clear(); + return; + } + final QuickFix[] fixes = descriptor.getFixes(); + if (fixes != null) { + MultiMap mapToUse = exist ? new MultiMap<>() : myMap; + for (QuickFix fix : fixes) { + mapToUse.putValue(fix.getName(), descriptor); + } + if (exist) { + for (String name : new ArrayList<>(myMap.keySet())) { + if (mapToUse.containsKey(name)) { + myMap.put(name, mapToUse.get(name)); + } + else { + myMap.remove(name); + } + } + } + } + } + + public static BatchProblemDescriptor single(@Nullable CommonProblemDescriptor descriptor) { + final BatchProblemDescriptor intersector = new BatchProblemDescriptor(false); + intersector.addProblem(descriptor); + return intersector; + } + + public int getProblemCount() { + return myDescriptors.size(); + } + + @Nullable + public PsiElement getFirstProblemElement() { + for (CommonProblemDescriptor descriptor : myDescriptors) { + if (descriptor == null) continue; + final PsiElement element = ((ProblemDescriptorBase)descriptor).getPsiElement(); + if (element != null) { + return element; + } + } + return null; + } + + public Set getQuickFixNames() { + LOG.assertTrue(!myOnlyCount); + return myMap.keySet(); + } + + public void applyFixes(final String name, final Project project) { + LOG.assertTrue(!myOnlyCount); + for (CommonProblemDescriptor descriptor : myMap.get(name)) { + final QuickFix[] fixes = descriptor.getFixes(); + LOG.assertTrue(fixes != null); + for (QuickFix fix : fixes) { + if (name.equals(fix.getName())) { + //noinspection unchecked + fix.applyFix(project, descriptor); + } + } + } + } + + public boolean isIntersectionTrivial() { + LOG.assertTrue(!myOnlyCount); + return myMap != null && myMap.isEmpty(); + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/Browser.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/Browser.java deleted file mode 100644 index ce8378d0b917..000000000000 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/Browser.java +++ /dev/null @@ -1,532 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.codeInspection.ui; - -import com.intellij.codeInsight.FileModificationService; -import com.intellij.codeInsight.daemon.HighlightDisplayKey; -import com.intellij.codeInspection.*; -import com.intellij.codeInspection.ex.*; -import com.intellij.codeInspection.reference.RefElement; -import com.intellij.codeInspection.reference.RefEntity; -import com.intellij.codeInspection.ui.actions.SuppressActionWrapper; -import com.intellij.ide.BrowserUtil; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.colors.EditorColorsScheme; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.profile.codeInspection.InspectionProjectProfileManagerImpl; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiManager; -import com.intellij.psi.util.PsiModificationTracker; -import com.intellij.ui.ScrollPaneFactory; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.ui.UIUtil; -import com.intellij.xml.util.XmlStringUtil; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import javax.swing.event.HyperlinkEvent; -import javax.swing.event.HyperlinkListener; -import javax.swing.text.Document; -import javax.swing.text.Style; -import javax.swing.text.StyleConstants; -import javax.swing.text.StyledDocument; -import javax.swing.text.html.HTMLDocument; -import javax.swing.text.html.HTMLFrameHyperlinkEvent; -import java.awt.*; -import java.io.IOException; -import java.io.StringReader; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -class Browser extends JPanel { - private static final String UNDER_CONSTRUCTION = InspectionsBundle.message("inspection.tool.description.under.construction.text"); - private final List myClickListeners = ContainerUtil.createLockFreeCopyOnWriteList(); - private RefEntity myCurrentEntity; - private JEditorPane myHTMLViewer; - private final InspectionResultsView myView; - private final HyperlinkListener myHyperLinkListener; - private CommonProblemDescriptor myCurrentDescriptor; - - public static class ClickEvent { - public static final int REF_ELEMENT = 1; - public static final int FILE_OFFSET = 2; - private final VirtualFile myFile; - private final int myStartPosition; - private final int myEndPosition; - private final RefElement refElement; - private final int myEventType; - - public ClickEvent(VirtualFile myFile, int myStartPosition, int myEndPosition) { - this.myFile = myFile; - this.myStartPosition = myStartPosition; - this.myEndPosition = myEndPosition; - myEventType = FILE_OFFSET; - refElement = null; - } - - public int getEventType() { - return myEventType; - } - - public VirtualFile getFile() { - return myFile; - } - - public int getStartOffset() { - return myStartPosition; - } - - public int getEndOffset() { - return myEndPosition; - } - - public RefElement getClickedElement() { - return refElement; - } - - } - - public void dispose(){ - removeAll(); - if (myHTMLViewer != null) { - myHTMLViewer.removeHyperlinkListener(myHyperLinkListener); - myHTMLViewer = null; - } - myClickListeners.clear(); - } - - public interface ClickListener { - void referenceClicked(ClickEvent e); - } - - private void showPageFromHistory(@NotNull RefEntity newEntity) { - InspectionToolWrapper toolWrapper = getToolWrapper(newEntity); - try { - String html = generateHTML(newEntity, toolWrapper); - myHTMLViewer.read(new StringReader(html), null); - setupStyle(); - myHTMLViewer.setCaretPosition(0); - } - catch (Exception e) { - showEmpty(); - } - finally { - myCurrentEntity = newEntity; - myCurrentDescriptor = null; - } - } - - public void showPageFor(RefEntity refEntity, CommonProblemDescriptor descriptor) { - try { - String html = generateHTML(refEntity, descriptor); - myHTMLViewer.read(new StringReader(html), null); - setupStyle(); - myHTMLViewer.setCaretPosition(0); - } - catch (Exception e) { - showEmpty(); - } - finally { - myCurrentEntity = refEntity; - myCurrentDescriptor = descriptor; - } - } - - public void showPageFor(RefEntity newEntity) { - if (newEntity == null) { - showEmpty(); - return; - } - //multiple problems for one entity -> refresh browser - showPageFromHistory(newEntity.getRefManager().getRefinedElement(newEntity)); - } - - public Browser(@NotNull InspectionResultsView view) { - super(new BorderLayout()); - myView = view; - - myCurrentEntity = null; - myCurrentDescriptor = null; - - myHTMLViewer = new JEditorPane(UIUtil.HTML_MIME, InspectionsBundle.message("inspection.offline.view.empty.browser.text")); - myHTMLViewer.setEditable(false); - myHyperLinkListener = new HyperlinkListener() { - @Override - public void hyperlinkUpdate(HyperlinkEvent e) { - Browser.this.hyperlinkUpdate(e); - } - }; - myHTMLViewer.addHyperlinkListener(myHyperLinkListener); - - final JScrollPane pane = ScrollPaneFactory.createScrollPane(myHTMLViewer); - pane.setBorder(null); - add(pane, BorderLayout.CENTER); - setupStyle(); - } - - private void hyperlinkUpdate(HyperlinkEvent e) { - if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) { - return; - } - JEditorPane pane = (JEditorPane)e.getSource(); - if (e instanceof HTMLFrameHyperlinkEvent) { - HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent)e; - HTMLDocument doc = (HTMLDocument)pane.getDocument(); - doc.processHTMLFrameHyperlinkEvent(evt); - return; - } - URL url = null; - try { - url = e.getURL(); - @NonNls String ref = url.getRef(); - if (ref.startsWith("pos:")) { - int delimeterPos = ref.indexOf(':', "pos:".length() + 1); - String startPosition = ref.substring("pos:".length(), delimeterPos); - String endPosition = ref.substring(delimeterPos + 1); - Integer textStartOffset = new Integer(startPosition); - Integer textEndOffset = new Integer(endPosition); - String fileURL = url.toExternalForm(); - fileURL = fileURL.substring(0, fileURL.indexOf('#')); - VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(fileURL); - if (vFile != null) { - fireClickEvent(vFile, textStartOffset.intValue(), textEndOffset.intValue()); - } - } - else if (ref.startsWith("descr:")) { - if (myCurrentDescriptor instanceof ProblemDescriptor) { - PsiElement psiElement = ((ProblemDescriptor)myCurrentDescriptor).getPsiElement(); - if (psiElement == null) return; - VirtualFile vFile = psiElement.getContainingFile().getVirtualFile(); - if (vFile != null) { - TextRange range = ((ProblemDescriptorBase)myCurrentDescriptor).getTextRange(); - fireClickEvent(vFile, range.getStartOffset(), range.getEndOffset()); - } - } - } - else if (ref.startsWith("invoke:")) { - int actionNumber = Integer.parseInt(ref.substring("invoke:".length())); - InspectionToolWrapper toolWrapper = getToolWrapper(); - InspectionToolPresentation presentation = myView.getGlobalInspectionContext().getPresentation(toolWrapper); - QuickFixAction fixAction = presentation.getQuickFixes(new RefElement[]{(RefElement)myCurrentEntity})[actionNumber]; - fixAction.doApplyFix(new RefElement[]{(RefElement)myCurrentEntity}, myView); - } - else if (ref.startsWith("invokelocal:")) { - int actionNumber = Integer.parseInt(ref.substring("invokelocal:".length())); - if (actionNumber > -1) { - invokeLocalFix(actionNumber); - } - } else if (ref.startsWith("suppress:")){ - final SuppressActionWrapper.SuppressTreeAction[] suppressTreeActions = - new SuppressActionWrapper(myView.getProject(), getToolWrapper(), myView.getTree().getSelectionPaths()).getChildren(null); - final List activeActions = new ArrayList(); - for (SuppressActionWrapper.SuppressTreeAction suppressTreeAction : suppressTreeActions) { - if (suppressTreeAction.isAvailable()) activeActions.add(suppressTreeAction); - } - if (!activeActions.isEmpty()) { - int actionNumber = Integer.parseInt(ref.substring("suppress:".length())); - if (actionNumber > -1 && activeActions.size() > actionNumber) { - activeActions.get(actionNumber).actionPerformed(null); - } - } - } - else { - int offset = Integer.parseInt(ref); - String fileURL = url.toExternalForm(); - fileURL = fileURL.substring(0, fileURL.indexOf('#')); - VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(fileURL); - if (vFile == null) { - vFile = VfsUtil.findFileByURL(url); - } - if (vFile != null) { - fireClickEvent(vFile, offset, offset); - } - } - } - catch (Throwable t) { - if (url != null) { - BrowserUtil.browse(url); - } - } - } - - private void setupStyle() { - Document document = myHTMLViewer.getDocument(); - if (!(document instanceof StyledDocument)) { - return; - } - - StyledDocument styledDocument = (StyledDocument)document; - - EditorColorsManager colorsManager = EditorColorsManager.getInstance(); - EditorColorsScheme scheme = colorsManager.getGlobalScheme(); - - Style style = styledDocument.addStyle("active", null); - StyleConstants.setFontFamily(style, scheme.getEditorFontName()); - StyleConstants.setFontSize(style, scheme.getEditorFontSize()); - styledDocument.setCharacterAttributes(0, document.getLength(), style, false); - } - - public void addClickListener(ClickListener listener) { - myClickListeners.add(listener); - } - - private void fireClickEvent(VirtualFile file, int startPosition, int endPosition) { - ClickEvent e = new ClickEvent(file, startPosition, endPosition); - - for (ClickListener listener : myClickListeners) { - listener.referenceClicked(e); - } - } - - private String generateHTML(final RefEntity refEntity, @NotNull final InspectionToolWrapper toolWrapper) { - final StringBuffer buf = new StringBuffer(); - final HTMLComposerImpl htmlComposer = getPresentation(toolWrapper).getComposer(); - if (refEntity instanceof RefElement) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - htmlComposer.compose(buf, refEntity); - } - }); - } - else { - htmlComposer.compose(buf, refEntity); - } - - uppercaseFirstLetter(buf); - - if (refEntity instanceof RefElement){ - appendSuppressSection(buf); - } - - insertHeaderFooter(buf); - - return buf.toString(); - } - - private InspectionToolPresentation getPresentation(@NotNull InspectionToolWrapper toolWrapper) { - return myView.getGlobalInspectionContext().getPresentation(toolWrapper); - } - - @SuppressWarnings({"HardCodedStringLiteral"}) - private static void insertHeaderFooter(final StringBuffer buf) { - buf.insert(0, ""); - buf.append(""); - } - - private String generateHTML(final RefEntity refEntity, final CommonProblemDescriptor descriptor) { - final StringBuffer buf = new StringBuffer(); - final Runnable action = new Runnable() { - @Override - public void run() { - InspectionToolWrapper toolWrapper = getToolWrapper(refEntity); - getPresentation(toolWrapper).getComposer().compose(buf, refEntity, descriptor); - } - }; - ApplicationManager.getApplication().runReadAction(action); - - uppercaseFirstLetter(buf); - - if (refEntity instanceof RefElement) { - appendSuppressSection(buf); - } - - insertHeaderFooter(buf); - return buf.toString(); - } - - private InspectionToolWrapper getToolWrapper(final RefEntity refEntity) { - InspectionToolWrapper toolWrapper = getToolWrapper(); - assert toolWrapper != null; - final GlobalInspectionContextImpl context = myView.getGlobalInspectionContext(); - if (refEntity instanceof RefElement){ - PsiElement element = ((RefElement)refEntity).getElement(); - if (element == null) return toolWrapper; - InspectionProfileWrapper profileWrapper = InspectionProjectProfileManagerImpl.getInstanceImpl(context.getProject()).getProfileWrapper(); - toolWrapper = profileWrapper.getInspectionTool(toolWrapper.getShortName(), element); - } - return toolWrapper; - } - - private void appendSuppressSection(final StringBuffer buf) { - final InspectionToolWrapper toolWrapper = getToolWrapper(); - if (toolWrapper != null) { - final HighlightDisplayKey key = HighlightDisplayKey.find(toolWrapper.getShortName()); - if (key != null){//dummy entry points - final SuppressActionWrapper.SuppressTreeAction[] suppressActions = new SuppressActionWrapper(myView.getProject(), toolWrapper, myView.getTree().getSelectionPaths()).getChildren(null); - if (suppressActions.length > 0) { - final List activeSuppressActions = new ArrayList(); - for (SuppressActionWrapper.SuppressTreeAction suppressAction : suppressActions) { - if (suppressAction.isAvailable()) { - activeSuppressActions.add(suppressAction); - } - } - if (!activeSuppressActions.isEmpty()) { - int idx = 0; - @NonNls final String br = "
"; - buf.append(br); - HTMLComposerImpl.appendHeading(buf, InspectionsBundle.message("inspection.export.results.suppress")); - for (AnAction suppressAction : activeSuppressActions) { - buf.append(br); - if (idx == activeSuppressActions.size() - 1) { - buf.append(br); - } - HTMLComposer.appendAfterHeaderIndention(buf); - @NonNls final String href = "" + suppressAction.getTemplatePresentation().getText() + ""; - buf.append(href); - idx++; - } - } - } - } - } - } - - private static void uppercaseFirstLetter(final StringBuffer buf) { - if (buf.length() > 1) { - char[] firstLetter = new char[1]; - buf.getChars(0, 1, firstLetter, 0); - buf.setCharAt(0, Character.toUpperCase(firstLetter[0])); - } - } - - @SuppressWarnings({"HardCodedStringLiteral"}) - public void showEmpty() { - myCurrentEntity = null; - try { - myHTMLViewer.read(new StringReader(InspectionsBundle.message("inspection.offline.view.empty.browser.text")), null); - } - catch (IOException e) { - //can't be - } - } - - public void showDescription(@NotNull InspectionToolWrapper toolWrapper){ - if (toolWrapper.getShortName().isEmpty()){ - showEmpty(); - return; - } - @NonNls StringBuffer page = new StringBuffer(); - page.append(""); - page.append(""); - page.append("" + - ""); - page.append(""); - page.append(""); - page.append("" + - "
"); - HTMLComposer.appendHeading(page, InspectionsBundle.message("inspection.tool.in.browser.id.title")); - page.append("
"); - page.append(toolWrapper.getShortName()); - page.append("
"); - HTMLComposer.appendHeading(page, InspectionsBundle.message("inspection.tool.in.browser.description.title")); - page.append("
"); - @NonNls final String underConstruction = "" + UNDER_CONSTRUCTION + ""; - try { - @NonNls String description = toolWrapper.loadDescription(); - if (description == null) { - description = underConstruction; - } - page.append(DefaultInspectionToolPresentation.stripUIRefsFromInspectionDescription(UIUtil.getHtmlBody(description))); - - page.append("
"); - myHTMLViewer.setText(XmlStringUtil.wrapInHtml(page)); - setupStyle(); - } - finally { - myCurrentEntity = null; - } - } - - @Nullable - private InspectionToolWrapper getToolWrapper() { - return myView.getTree().getSelectedToolWrapper(); - } - - public void invokeLocalFix(int idx) { - if (myView.getTree().getSelectionCount() != 1) return; - final InspectionTreeNode node = (InspectionTreeNode)myView.getTree().getSelectionPath().getLastPathComponent(); - if (node instanceof ProblemDescriptionNode) { - final ProblemDescriptionNode problemNode = (ProblemDescriptionNode)node; - final CommonProblemDescriptor descriptor = problemNode.getDescriptor(); - final RefEntity element = problemNode.getElement(); - invokeFix(element, descriptor, idx); - } - else if (node instanceof RefElementNode) { - RefElementNode elementNode = (RefElementNode)node; - RefEntity element = elementNode.getElement(); - CommonProblemDescriptor descriptor = elementNode.getProblem(); - if (descriptor != null) { - invokeFix(element, descriptor, idx); - } - } - } - - private void invokeFix(final RefEntity element, final CommonProblemDescriptor descriptor, final int idx) { - final QuickFix[] fixes = descriptor.getFixes(); - if (fixes != null && fixes.length > idx && fixes[idx] != null) { - if (element instanceof RefElement) { - PsiElement psiElement = ((RefElement)element).getElement(); - if (psiElement != null && psiElement.isValid()) { - if (!FileModificationService.getInstance().preparePsiElementForWrite(psiElement)) return; - performFix(element, descriptor, idx, fixes[idx]); - } - } - else { - performFix(element, descriptor, idx, fixes[idx]); - } - } - } - - private void performFix(final RefEntity element, final CommonProblemDescriptor descriptor, final int idx, final QuickFix fix) { - final Runnable command = new Runnable() { - @Override - public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - final PsiModificationTracker tracker = PsiManager.getInstance(myView.getProject()).getModificationTracker(); - final long startCount = tracker.getModificationCount(); - CommandProcessor.getInstance().markCurrentCommandAsGlobal(myView.getProject()); - //CCE here means QuickFix was incorrectly inherited - fix.applyFix(myView.getProject(), descriptor); - if (startCount != tracker.getModificationCount()) { - InspectionToolWrapper toolWrapper = myView.getTree().getSelectedToolWrapper(); - if (toolWrapper != null) { - InspectionToolPresentation presentation = - myView.getGlobalInspectionContext().getPresentation(toolWrapper); - presentation.ignoreProblem(element, descriptor, idx); - } - myView.updateView(false); - } - } - }); - } - }; - CommandProcessor.getInstance().executeCommand(myView.getProject(), command, fix.getName(), null); - } -} - diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNode.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNode.java index 0bb3105e8ef7..b923325f3aab 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNode.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNode.java @@ -23,7 +23,6 @@ import com.intellij.util.IconUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import java.util.Enumeration; /** * @author max @@ -51,19 +50,9 @@ public class InspectionNode extends InspectionTreeNode { } public boolean isTooBigForOnlineRefresh() { - if(!myTooBigForOnlineRefresh) myTooBigForOnlineRefresh = getProblemCount()>1000; + if (!myTooBigForOnlineRefresh) { + myTooBigForOnlineRefresh = accumulateProblemInfo(new BatchProblemDescriptor(true)).getProblemCount() > 1000; + } return myTooBigForOnlineRefresh; } - - @Override - public int getProblemCount() { - int sum = 0; - Enumeration children = children(); - while (children.hasMoreElements()) { - InspectionTreeNode child = (InspectionTreeNode)children.nextElement(); - if (child instanceof InspectionNode) continue; - sum += child.getProblemCount(); - } - return sum; - } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java new file mode 100644 index 000000000000..9f33f36868d0 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java @@ -0,0 +1,103 @@ +/* + * 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. + */ +package com.intellij.codeInspection.ui; + +import com.intellij.codeInsight.daemon.HighlightDisplayKey; +import com.intellij.codeInspection.ModifiableModel; +import com.intellij.codeInspection.ex.DisableInspectionToolAction; +import com.intellij.codeInspection.ex.InspectionProfileImpl; +import com.intellij.codeInspection.ex.InspectionToolWrapper; +import com.intellij.openapi.project.Project; +import com.intellij.profile.codeInspection.InspectionProjectProfileManager; +import com.intellij.psi.PsiElement; +import com.intellij.ui.*; +import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.util.Consumer; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseEvent; + +/** + * @author Dmitry Batkovich + */ +public class InspectionNodeInfo extends JPanel { + private final JButton myButton; + private final SimpleColoredComponent myTitle; + private final HighlightDisplayKey myKey; + private final InspectionProfileImpl myCurrentProfile; + private final String myName; + private final Project myProject; + + public InspectionNodeInfo(final InspectionToolWrapper toolWrapper, Project project) { + setLayout(new GridBagLayout()); + setBorder(IdeBorderFactory.createEmptyBorder(new Insets(0, JBUI.scale(3), 0, 0))); + myProject = project; + myTitle = new SimpleColoredComponent(); + myCurrentProfile = (InspectionProfileImpl)InspectionProjectProfileManager.getInstance(project).getProjectProfileImpl(); + myKey = HighlightDisplayKey.find(toolWrapper.getID()); + myName = toolWrapper.getDisplayName(); + myButton = new JButton(); + + add(myTitle, + new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, JBUI.scale(2), 0, 0), + 0, 0)); + add(new JBLabel(String.valueOf(toolWrapper.loadDescription()), UIUtil.ComponentStyle.SMALL), + new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, + new Insets(JBUI.scale(5), JBUI.scale(5), 0, 0), 0, 0)); + add(myButton, + new GridBagConstraints(0, 2, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, + new Insets(JBUI.scale(15), 0, 0, 0), 0, 0)); + updateEnableButtonText(false); + + new ClickListener() { + @Override + public boolean onClick(@NotNull MouseEvent event, int clickCount) { + updateEnableButtonText(true); + return true; + } + }.installOn(myButton); + } + + private void updateEnableButtonText(boolean revert) { + boolean isEnabled = myCurrentProfile.isToolEnabled(myKey); + if (revert) { + final boolean isEnabledAsFinal = isEnabled; + DisableInspectionToolAction.modifyAndCommitProjectProfile(new Consumer() { + @Override + public void consume(ModifiableModel model) { + if (isEnabledAsFinal) { + model.disableTool(myKey.getID(), myProject); + } + else { + ((InspectionProfileImpl)model).enableTool(myKey.getID(), myProject); + } + } + }, myProject); + isEnabled = !isEnabled; + } + myButton.setText((isEnabled ? "Disable" : "Enable") + " inspection"); + myTitle.clear(); + myTitle.append(myName); + if (!isEnabled) { + myTitle.append(" Disabled", SimpleTextAttributes.GRAYED_ATTRIBUTES); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 8f9eb15614d8..0d065020d5c7 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -21,7 +21,6 @@ import com.intellij.analysis.AnalysisScope; import com.intellij.analysis.AnalysisUIOptions; import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInsight.daemon.HighlightDisplayKey; -import com.intellij.codeInsight.highlighting.HighlightManager; import com.intellij.codeInspection.*; import com.intellij.codeInspection.ex.*; import com.intellij.codeInspection.reference.RefElement; @@ -36,11 +35,8 @@ import com.intellij.injected.editor.VirtualFileWindow; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.colors.EditorColors; -import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.markup.TextAttributes; -import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.*; import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; @@ -52,14 +48,17 @@ import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.pom.Navigatable; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; +import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.*; +import com.intellij.usageView.UsageInfo; +import com.intellij.usages.impl.UsagePreviewPanel; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.EditSourceOnDoubleClickHandler; import com.intellij.util.OpenSourceUtil; -import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.*; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NonNls; @@ -80,6 +79,7 @@ import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.*; +import java.util.HashSet; import java.util.List; import java.util.concurrent.ConcurrentMap; @@ -87,11 +87,12 @@ import java.util.concurrent.ConcurrentMap; * @author max */ public class InspectionResultsView extends JPanel implements Disposable, OccurenceNavigator, DataProvider { + private static final Logger LOG = Logger.getInstance(InspectionResultsView.class); + public static final DataKey DATA_KEY = DataKey.create("inspectionView"); private final Project myProject; private final InspectionTree myTree; - private final Browser myBrowser; private final ConcurrentMap> myGroups = ContainerUtil.newConcurrentMap(); private final OccurenceNavigator myOccurenceNavigator; private volatile InspectionProfile myInspectionProfile; @@ -129,12 +130,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren myOccurenceNavigator = initOccurenceNavigator(); - myBrowser = new Browser(this); - mySplitter = new OnePixelSplitter(false, AnalysisUIOptions.getInstance(myProject).SPLITTER_PROPORTION); mySplitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myTree, SideBorder.LEFT | SideBorder.RIGHT)); - mySplitter.setSecondComponent(myBrowser); mySplitter.addPropertyChangeListener(new PropertyChangeListener() { @Override @@ -146,30 +144,6 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren }); add(mySplitter, BorderLayout.CENTER); - myBrowser.addClickListener(new Browser.ClickListener() { - @Override - public void referenceClicked(final Browser.ClickEvent e) { - if (e.getEventType() == Browser.ClickEvent.REF_ELEMENT) { - final RefElement refElement = e.getClickedElement(); - final OpenFileDescriptor descriptor = getOpenFileDescriptor(refElement); - if (descriptor != null) { - FileEditorManager.getInstance(project).openTextEditor(descriptor, false); - } - } - else if (e.getEventType() == Browser.ClickEvent.FILE_OFFSET) { - final VirtualFile file = e.getFile(); - final OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file, e.getStartOffset()); - final Editor editor = FileEditorManager.getInstance(project).openTextEditor(descriptor, true); - if (editor != null) { - final TextAttributes selectionAttributes = - EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); - HighlightManager.getInstance(project) - .addRangeHighlight(editor, e.getStartOffset(), e.getEndOffset(), selectionAttributes, true, null); - } - } - } - }); - createActionsToolbar(); TreeUtil.selectFirstNode(myTree); } @@ -366,7 +340,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren @Override public void dispose(){ mySplitter.dispose(); - myBrowser.dispose(); + //myBrowser.dispose(); myInspectionProfile = null; myDisposed = true; } @@ -408,7 +382,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private void syncBrowser() { if (myTree.getSelectionModel().getSelectionCount() != 1) { - myBrowser.showEmpty(); + //myBrowser.showEmpty(); } else { TreePath pathSelected = myTree.getSelectionModel().getLeadSelectionPath(); @@ -418,46 +392,84 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren final RefElementNode refElementNode = (RefElementNode)node; final CommonProblemDescriptor problem = refElementNode.getProblem(); final RefEntity refSelected = refElementNode.getElement(); - if (problem != null) { - showInBrowser(refSelected, problem); + if (node.isLeaf()) { + LOG.assertTrue(problem != null); + showInBrowser(refSelected, BatchProblemDescriptor.single(problem)); } else { - showInBrowser(refSelected); + showInBrowser(refSelected, node.accumulateProblemInfo(new BatchProblemDescriptor(false))); } } else if (node instanceof ProblemDescriptionNode) { final ProblemDescriptionNode problemNode = (ProblemDescriptionNode)node; - showInBrowser(problemNode.getElement(), problemNode.getDescriptor()); + showInBrowser(problemNode.getElement(), BatchProblemDescriptor.single(problemNode.getDescriptor())); } else if (node instanceof InspectionNode) { - showInBrowser(((InspectionNode)node).getToolWrapper()); + showInBrowser(null, node.accumulateProblemInfo(new BatchProblemDescriptor(false))); } else { - myBrowser.showEmpty(); + mySplitter.setSecondComponent(new JPanel()); } } } } - private void showInBrowser(final RefEntity refEntity) { + private void showInBrowser(final RefEntity refEntity, BatchProblemDescriptor intersector) { + //todo use refentity to determine Cursor currentCursor = getCursor(); setCursor(new Cursor(Cursor.WAIT_CURSOR)); - myBrowser.showPageFor(refEntity); + + if (intersector != null) { + final JPanel editorPanel = new JPanel(); + editorPanel.setLayout(new BorderLayout()); + + final PsiElement containingElement = refEntity instanceof RefElement ? ((RefElement)refEntity).getElement() : null; + final QuickFixToolbar toolbar = new QuickFixToolbar(intersector, + myTree.getSelectedToolWrapper(), + myTree.getSelectionPaths(), + myProject, + containingElement); + editorPanel.add(toolbar, BorderLayout.NORTH); + editorPanel.add(createBaseRightComponentFor(containingElement, intersector), BorderLayout.CENTER); + mySplitter.setSecondComponent(editorPanel); + } setCursor(currentCursor); } - private void showInBrowser(@NotNull InspectionToolWrapper toolWrapper) { - Cursor currentCursor = getCursor(); - setCursor(new Cursor(Cursor.WAIT_CURSOR)); - myBrowser.showDescription(toolWrapper); - setCursor(currentCursor); - } + private JComponent createBaseRightComponentFor(PsiElement containingElement, BatchProblemDescriptor descriptor) { + final int count = descriptor.getProblemCount(); + if (count == 1 || containingElement != null) { + final PsiElement element = descriptor.getFirstProblemElement(); + LOG.assertTrue(element != null); + final PsiElement referencedElement = containingElement == null ? descriptor.getFirstProblemElement() : containingElement; + final PsiFile file = referencedElement.getContainingFile(); + final Document document = PsiDocumentManager.getInstance(referencedElement.getProject()).getDocument(file); + Editor editor = EditorFactory.getInstance().createEditor(document, myProject, file.getVirtualFile(), true); + final EditorSettings settings = editor.getSettings(); + settings.setLineNumbersShown(false); + settings.setLineNumbersShown(false); + settings.setWhitespacesShown(false); + settings.setLineMarkerAreaShown(false); + settings.setIndentGuidesShown(false); + settings.setFoldingOutlineShown(false); + settings.setAdditionalColumnsCount(0); + settings.setAdditionalLinesCount(0); + settings.setRightMarginShown(true); + settings.setRightMargin(60); - private void showInBrowser(final RefEntity refEntity, CommonProblemDescriptor descriptor) { - Cursor currentCursor = getCursor(); - setCursor(new Cursor(Cursor.WAIT_CURSOR)); - myBrowser.showPageFor(refEntity, descriptor); - setCursor(currentCursor); + editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + editor.getCaretModel().moveToOffset(referencedElement.getTextOffset()); + editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + UsagePreviewPanel + .highlight(containingElement == null ? Collections.singletonList(new UsageInfo(referencedElement)) : Collections.emptyList(), + editor, myProject); + return editor.getComponent(); + } + else if (count > 1) { + return new InspectionNodeInfo(myTree.getSelectedToolWrapper(), myProject); + } + //TODO must not happen + return new JPanel(); } @NotNull @@ -905,4 +917,19 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } } } + + private static RefEntity findLeafIfOnlyOne(@NotNull RefEntity entity) { + RefEntity current = entity; + while (current != null) { + final List children = current.getChildren(); + if (children.size() > 1) { + return null; + } + if (children.isEmpty()) { + return current; + } + current = children.get(0); + } + return null; + } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java index d1c3c3a2d7f1..474c78b70e41 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java @@ -258,7 +258,7 @@ public class InspectionTree extends Tree { append(node.toString(), patchAttr(node, appearsBold(node) ? SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES : getMainForegroundAttributes(node))); - int problemCount = node.getProblemCount(); + int problemCount = node.accumulateProblemInfo(new BatchProblemDescriptor(true)).getProblemCount(); if (!leaf) { append(" " + InspectionsBundle.message("inspection.problem.descriptor.count", problemCount), patchAttr(node, SimpleTextAttributes.GRAYED_ATTRIBUTES)); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeNode.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeNode.java index 11977eb09dca..0f90b155dff8 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeNode.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeNode.java @@ -35,14 +35,13 @@ public abstract class InspectionTreeNode extends DefaultMutableTreeNode { @Nullable public abstract Icon getIcon(boolean expanded); - public int getProblemCount() { - int sum = 0; + public BatchProblemDescriptor accumulateProblemInfo(BatchProblemDescriptor accumulator) { Enumeration enumeration = children(); while (enumeration.hasMoreElements()) { InspectionTreeNode child = (InspectionTreeNode)enumeration.nextElement(); - sum += child.getProblemCount(); + child.accumulateProblemInfo(accumulator); } - return sum; + return accumulator; } public boolean isValid() { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java index 18e41a82f62c..bf89ddafdf5e 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java @@ -88,8 +88,9 @@ public class ProblemDescriptionNode extends InspectionTreeNode { } @Override - public int getProblemCount() { - return 1; + public BatchProblemDescriptor accumulateProblemInfo(BatchProblemDescriptor accumulator) { + accumulator.addProblem(getDescriptor()); + return accumulator; } @Override diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java new file mode 100644 index 000000000000..df233172ded0 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -0,0 +1,170 @@ +/* + * 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. + */ +package com.intellij.codeInspection.ui; + +import com.intellij.codeInspection.ex.InspectionToolWrapper; +import com.intellij.codeInspection.ui.actions.SuppressActionWrapper; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.actionSystem.ex.ComboBoxAction; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Couple; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; +import com.intellij.ui.ClickListener; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.components.JBLabel; +import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.tree.TreePath; +import java.awt.*; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.function.Supplier; + +/** + * @author Dmitry Batkovich + */ +public class QuickFixToolbar extends JPanel { + @NotNull private final Project myProject; + + public QuickFixToolbar(@NotNull BatchProblemDescriptor descriptor, + @NotNull InspectionToolWrapper toolWrapper, + @NotNull TreePath[] paths, + @NotNull Project project, + @Nullable PsiElement containingElement) { + + myProject = project; + final Set fixes = descriptor.getQuickFixNames(); + final boolean hasFixes = fixes != null && !fixes.isEmpty(); + final boolean multipleDescriptors = descriptor.getProblemCount() > 1; + + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + List panels = new ArrayList<>(); + for (int i = 0; i < (multipleDescriptors ? 2 : 1); i++) { + final JPanel line = new JPanel(); + line.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); + panels.add((JPanel)add(line)); + } + if (multipleDescriptors) { + panels.get(0).setBorder(IdeBorderFactory.createEmptyBorder(new Insets(JBUI.scale(5), 0, 0, 0))); + } + + fill(getBulbPlacement(hasFixes), QuickFixToolbar::createBulbIcon, panels); + fill(getDescriptionLabelPlacement(hasFixes, multipleDescriptors), + () -> getLabel(hasFixes, (PsiNamedElement)containingElement, descriptor.getProblemCount()), panels); + fill(getFixesPlacement(hasFixes, multipleDescriptors), () -> createFixPanel(descriptor, project, fixes), panels); + fill(getSuppressPlacement(hasFixes, multipleDescriptors), () -> createSuppressionCombo(toolWrapper, paths, project), panels); + } + + @NotNull + private JLabel getLabel(boolean hasFixes, PsiNamedElement target, int problemsCount) { + final JBLabel label = + new JBLabel((hasFixes ? " Fix " : " ") + problemsCount + " warnings " + (target == null ? "" : ("in " + target.getName()))); + Font font = label.getFont(); + if (!hasFixes) { + label.setBorder(IdeBorderFactory.createEmptyBorder(new Insets(JBUI.scale(0), JBUI.scale(3), JBUI.scale(6), 0))); + } + label.setFont(new Font(font.getFontName(), Font.BOLD, font.getSize())); + return label; + } + + @NotNull + private static JLabel createBulbIcon() { + final JLabel label = new JLabel(AllIcons.Actions.IntentionBulb); + label.setBorder(IdeBorderFactory.createEmptyBorder(new Insets(0, JBUI.scale(10), 0, 0))); + return label; + } + + private static JComponent createSuppressionCombo(@NotNull final InspectionToolWrapper toolWrapper, + @NotNull final TreePath[] paths, + @NotNull final Project project) { + final ComboBoxAction action = new ComboBoxAction() { + { + getTemplatePresentation().setText("Suppress"); + } + + @NotNull + @Override + protected DefaultActionGroup createPopupActionGroup(JComponent button) { + final DefaultActionGroup group = new DefaultActionGroup(); + group.addAll(new SuppressActionWrapper(project, toolWrapper, paths).getChildren(null)); + return group; + } + }; + action.setSmallVariant(false); + return action.createCustomComponent(action.getTemplatePresentation()); + } + + @NotNull + private JPanel createFixPanel(@NotNull final BatchProblemDescriptor descriptor, @NotNull final Project project, Set fixes) { + JPanel fixPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, JBUI.scale(3), JBUI.scale(5))); + for (String fixName : fixes) { + final JButton quickFixButton = new JButton(fixName); + fixPanel.add(quickFixButton); + new ClickListener() { + @Override + public boolean onClick(@NotNull MouseEvent event, int clickCount) { + WriteCommandAction.runWriteCommandAction(myProject, () -> { + descriptor.applyFixes(fixName, project); + }); + setVisible(false); + return true; + } + }.installOn(quickFixButton); + } + return fixPanel; + } + + private static void fill(@Nullable Couple point, + @NotNull Supplier componentSupplier, + @NotNull List parent) { + if (point == null) { + return; + } + final int y = point.getSecond(); + final JPanel row = parent.get(y); + row.add(componentSupplier.get()); + } + + @NotNull + private static Couple getSuppressPlacement(boolean hasQuickFixes, boolean multipleDescriptors) { + return hasQuickFixes + ? multipleDescriptors ? Couple.of(1, 1) : Couple.of(2, 0) + : Couple.of(0, multipleDescriptors ? 1 : 0); + } + + @Nullable + private static Couple getFixesPlacement(boolean hasQuickFixes, boolean multipleDescriptors) { + return hasQuickFixes ? multipleDescriptors ? Couple.of(0, 1) : Couple.of(1, 0) : null; + } + + @Nullable + private static Couple getDescriptionLabelPlacement(boolean hasQuickFixes, boolean multipleDescriptors) { + return multipleDescriptors ? Couple.of(hasQuickFixes ? 1 : 0, 0) : null; + } + + @Nullable + private static Couple getBulbPlacement(boolean hasQuickFixes) { + return hasQuickFixes ? Couple.of(0, 0) : null; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/RefElementNode.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/RefElementNode.java index bfd717fc518c..1c7642539d05 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/RefElementNode.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/RefElementNode.java @@ -71,11 +71,6 @@ public class RefElementNode extends InspectionTreeNode { return myIcon.getIcon(); } - @Override - public int getProblemCount() { - return Math.max(1, super.getProblemCount()); - } - public String toString() { final RefEntity element = getElement(); if (element == null || !element.isValid()) { diff --git a/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java b/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java index 5fee98914ee5..0a8ebc218f55 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java @@ -18,6 +18,7 @@ package com.intellij.usages.impl; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.colors.EditorColors; @@ -108,22 +109,30 @@ public class UsagePreviewPanel extends UsageContextPanelBase { revalidate(); } - final Editor editor = myEditor; - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (myProject.isDisposed()) return; - highlight(infos, editor); - } - }); + highlight(infos, myEditor, myProject); } private static final Key IN_PREVIEW_USAGE_FLAG = Key.create("IN_PREVIEW_USAGE_FLAG"); - private void highlight(@NotNull List infos, @NotNull Editor editor) { - if (editor != myEditor) return; //already disposed - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - MarkupModel markupModel = myEditor.getMarkupModel(); + + public static void highlight(@NotNull final List infos, @NotNull final Editor editor, @NotNull final Project project) { + @SuppressWarnings("UnnecessaryLocalVariable") final Editor editor1 = editor; + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (project.isDisposed()) return; + //noinspection ConstantConditions + if (editor1 == editor) { + doHighlight(infos, editor, project); + } + } + }, ModalityState.NON_MODAL); + } + + private static void doHighlight(@NotNull List infos, @NotNull Editor editor, @NotNull Project project) { + PsiDocumentManager.getInstance(project).commitAllDocuments(); + + MarkupModel markupModel = editor.getMarkupModel(); for (RangeHighlighter highlighter : markupModel.getAllHighlighters()) { if (highlighter.getUserData(IN_PREVIEW_USAGE_FLAG) != null) { highlighter.dispose(); @@ -154,15 +163,15 @@ public class UsagePreviewPanel extends UsageContextPanelBase { } } // highlight injected element in host document textrange - textRange = InjectedLanguageManager.getInstance(myProject).injectedToHost(psiElement, textRange); + textRange = InjectedLanguageManager.getInstance(project).injectedToHost(psiElement, textRange); RangeHighlighter highlighter = markupModel.addRangeHighlighter(textRange.getStartOffset(), textRange.getEndOffset(), HighlighterLayer.ADDITIONAL_SYNTAX, attributes, HighlighterTargetArea.EXACT_RANGE); highlighter.putUserData(IN_PREVIEW_USAGE_FLAG, Boolean.TRUE); - myEditor.getCaretModel().moveToOffset(textRange.getEndOffset()); + editor.getCaretModel().moveToOffset(textRange.getEndOffset()); } - myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); } private static final Key PREVIEW_EDITOR_FLAG = Key.create("PREVIEW_EDITOR_FLAG"); From ff2c0e661953f54b970f270c5ff332880386a603 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 11 Feb 2016 12:29:26 +0300 Subject: [PATCH 02/84] inspection toolwindow: exception when node element is directory --- .../intellij/codeInspection/ui/InspectionResultsView.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 0d065020d5c7..7e428b555fc4 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -48,9 +48,7 @@ import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.pom.Navigatable; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; +import com.intellij.psi.*; import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.*; import com.intellij.usageView.UsageInfo; @@ -438,7 +436,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private JComponent createBaseRightComponentFor(PsiElement containingElement, BatchProblemDescriptor descriptor) { final int count = descriptor.getProblemCount(); - if (count == 1 || containingElement != null) { + if (count == 1 || (containingElement != null && !(containingElement instanceof PsiDirectory))) { final PsiElement element = descriptor.getFirstProblemElement(); LOG.assertTrue(element != null); final PsiElement referencedElement = containingElement == null ? descriptor.getFirstProblemElement() : containingElement; @@ -457,7 +455,6 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren settings.setRightMarginShown(true); settings.setRightMargin(60); - editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); editor.getCaretModel().moveToOffset(referencedElement.getTextOffset()); editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); UsagePreviewPanel From d5cd89c971240a47abecf466d7f759338b3f5a5c Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 11 Feb 2016 12:42:28 +0300 Subject: [PATCH 03/84] inspection toolwindow: release preview editor --- .../ui/InspectionResultsView.java | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 7e428b555fc4..be211d0e7512 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -109,6 +109,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private final InspectionRVContentProvider myProvider; private AnAction myIncludeAction; private AnAction myExcludeAction; + private Editor myPreviewEditor; public InspectionResultsView(@NotNull final Project project, final InspectionProfile inspectionProfile, @@ -436,14 +437,18 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private JComponent createBaseRightComponentFor(PsiElement containingElement, BatchProblemDescriptor descriptor) { final int count = descriptor.getProblemCount(); + if (myPreviewEditor != null) { + EditorFactory.getInstance().releaseEditor(myPreviewEditor); + myPreviewEditor = null; + } if (count == 1 || (containingElement != null && !(containingElement instanceof PsiDirectory))) { final PsiElement element = descriptor.getFirstProblemElement(); LOG.assertTrue(element != null); final PsiElement referencedElement = containingElement == null ? descriptor.getFirstProblemElement() : containingElement; final PsiFile file = referencedElement.getContainingFile(); final Document document = PsiDocumentManager.getInstance(referencedElement.getProject()).getDocument(file); - Editor editor = EditorFactory.getInstance().createEditor(document, myProject, file.getVirtualFile(), true); - final EditorSettings settings = editor.getSettings(); + myPreviewEditor = EditorFactory.getInstance().createEditor(document, myProject, file.getVirtualFile(), true); + final EditorSettings settings = myPreviewEditor.getSettings(); settings.setLineNumbersShown(false); settings.setLineNumbersShown(false); settings.setWhitespacesShown(false); @@ -455,12 +460,14 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren settings.setRightMarginShown(true); settings.setRightMargin(60); - editor.getCaretModel().moveToOffset(referencedElement.getTextOffset()); - editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + myPreviewEditor.getCaretModel().moveToOffset(referencedElement.getTextOffset()); + myPreviewEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); UsagePreviewPanel - .highlight(containingElement == null ? Collections.singletonList(new UsageInfo(referencedElement)) : Collections.emptyList(), - editor, myProject); - return editor.getComponent(); + .highlight(containingElement == null + ? Collections.singletonList(new UsageInfo(referencedElement)) + : getElementToHighlight(containingElement), + myPreviewEditor, myProject); + return myPreviewEditor.getComponent(); } else if (count > 1) { return new InspectionNodeInfo(myTree.getSelectedToolWrapper(), myProject); @@ -915,18 +922,14 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } } - private static RefEntity findLeafIfOnlyOne(@NotNull RefEntity entity) { - RefEntity current = entity; - while (current != null) { - final List children = current.getChildren(); - if (children.size() > 1) { - return null; - } - if (children.isEmpty()) { - return current; - } - current = children.get(0); + @NotNull + private static List getElementToHighlight(@Nullable PsiElement element) { + if (element instanceof PsiFile || element == null) { + return Collections.emptyList(); } - return null; + if (element instanceof PsiNameIdentifierOwner) { + return getElementToHighlight(((PsiNameIdentifierOwner)element).getNameIdentifier()); + } + return Collections.singletonList(new UsageInfo(element)); } } From 40c7c8d82ab62ddc74552cfe1836bc1ea05cbe2a Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 11 Feb 2016 12:56:14 +0300 Subject: [PATCH 04/84] inspection toolwindow: release preview editor 2 --- .../ui/InspectionResultsView.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index be211d0e7512..7cc2b8693db6 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -151,7 +151,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { @Override public void valueChanged(TreeSelectionEvent e) { - syncBrowser(); + syncRightPanel(); if (isAutoScrollMode()) { OpenSourceUtil.openSourcesFrom(DataManager.getInstance().getDataContext(InspectionResultsView.this), false); } @@ -337,9 +337,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } @Override - public void dispose(){ + public void dispose() { + releaseEditor(); mySplitter.dispose(); - //myBrowser.dispose(); myInspectionProfile = null; myDisposed = true; } @@ -379,7 +379,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren return null; } - private void syncBrowser() { + private void syncRightPanel() { if (myTree.getSelectionModel().getSelectionCount() != 1) { //myBrowser.showEmpty(); } @@ -393,18 +393,18 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren final RefEntity refSelected = refElementNode.getElement(); if (node.isLeaf()) { LOG.assertTrue(problem != null); - showInBrowser(refSelected, BatchProblemDescriptor.single(problem)); + showInRightPanel(refSelected, BatchProblemDescriptor.single(problem)); } else { - showInBrowser(refSelected, node.accumulateProblemInfo(new BatchProblemDescriptor(false))); + showInRightPanel(refSelected, node.accumulateProblemInfo(new BatchProblemDescriptor(false))); } } else if (node instanceof ProblemDescriptionNode) { final ProblemDescriptionNode problemNode = (ProblemDescriptionNode)node; - showInBrowser(problemNode.getElement(), BatchProblemDescriptor.single(problemNode.getDescriptor())); + showInRightPanel(problemNode.getElement(), BatchProblemDescriptor.single(problemNode.getDescriptor())); } else if (node instanceof InspectionNode) { - showInBrowser(null, node.accumulateProblemInfo(new BatchProblemDescriptor(false))); + showInRightPanel(null, node.accumulateProblemInfo(new BatchProblemDescriptor(false))); } else { mySplitter.setSecondComponent(new JPanel()); @@ -413,7 +413,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } } - private void showInBrowser(final RefEntity refEntity, BatchProblemDescriptor intersector) { + private void showInRightPanel(final RefEntity refEntity, BatchProblemDescriptor intersector) { //todo use refentity to determine Cursor currentCursor = getCursor(); setCursor(new Cursor(Cursor.WAIT_CURSOR)); @@ -437,10 +437,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private JComponent createBaseRightComponentFor(PsiElement containingElement, BatchProblemDescriptor descriptor) { final int count = descriptor.getProblemCount(); - if (myPreviewEditor != null) { - EditorFactory.getInstance().releaseEditor(myPreviewEditor); - myPreviewEditor = null; - } + releaseEditor(); if (count == 1 || (containingElement != null && !(containingElement instanceof PsiDirectory))) { final PsiElement element = descriptor.getFirstProblemElement(); LOG.assertTrue(element != null); @@ -932,4 +929,11 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } return Collections.singletonList(new UsageInfo(element)); } + + private void releaseEditor() { + if (myPreviewEditor != null) { + EditorFactory.getInstance().releaseEditor(myPreviewEditor); + myPreviewEditor = null; + } + } } From 15b6cb5325b4e66c53af2e9f960c76ea37d2ca01 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 11 Feb 2016 13:01:34 +0300 Subject: [PATCH 05/84] inspection toolwindow: show dummy panel for multiple selection --- .../intellij/codeInspection/ui/InspectionResultsView.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 7cc2b8693db6..92e5b7b4282d 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -57,6 +57,7 @@ import com.intellij.util.ConcurrencyUtil; import com.intellij.util.EditSourceOnDoubleClickHandler; import com.intellij.util.OpenSourceUtil; import com.intellij.util.containers.*; +import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NonNls; @@ -381,7 +382,10 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private void syncRightPanel() { if (myTree.getSelectionModel().getSelectionCount() != 1) { - //myBrowser.showEmpty(); + final JLabel multipleSelectionLabel = new JLabel("Select inspection tree node to see problem description"); + multipleSelectionLabel.setVerticalAlignment(SwingConstants.TOP); + multipleSelectionLabel.setBorder(IdeBorderFactory.createEmptyBorder(JBUI.scale(5), JBUI.scale(5), 0, 0)); + mySplitter.setSecondComponent(multipleSelectionLabel); } else { TreePath pathSelected = myTree.getSelectionModel().getLeadSelectionPath(); From 01294374940480acf1508840c189dee684474ab9 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 11 Feb 2016 14:56:56 +0300 Subject: [PATCH 06/84] inspection toolwindow: sort quick fixes & show quick fixes in combo if count > 3 --- .../ui/BatchProblemDescriptor.java | 6 ++ .../ui/InspectionResultsView.java | 2 +- .../codeInspection/ui/QuickFixToolbar.java | 92 +++++++++++++++---- 3 files changed, 83 insertions(+), 17 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java index 6ee0c81c9e1a..5729cabb0d9d 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java @@ -21,6 +21,7 @@ import com.intellij.codeInspection.QuickFix; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.Nullable; @@ -122,6 +123,11 @@ public class BatchProblemDescriptor { } } + public QuickFix findFixFor(String name) { + LOG.assertTrue(!myOnlyCount); + return ContainerUtil.getFirstItem(myMap.get(name)).getFixes()[0]; + } + public boolean isIntersectionTrivial() { LOG.assertTrue(!myOnlyCount); return myMap != null && myMap.isEmpty(); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 92e5b7b4282d..9bf60f92c0a9 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -391,6 +391,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren TreePath pathSelected = myTree.getSelectionModel().getLeadSelectionPath(); if (pathSelected != null) { final InspectionTreeNode node = (InspectionTreeNode)pathSelected.getLastPathComponent(); + releaseEditor(); if (node instanceof RefElementNode) { final RefElementNode refElementNode = (RefElementNode)node; final CommonProblemDescriptor problem = refElementNode.getProblem(); @@ -441,7 +442,6 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private JComponent createBaseRightComponentFor(PsiElement containingElement, BatchProblemDescriptor descriptor) { final int count = descriptor.getProblemCount(); - releaseEditor(); if (count == 1 || (containingElement != null && !(containingElement instanceof PsiDirectory))) { final PsiElement element = descriptor.getFirstProblemElement(); LOG.assertTrue(element != null); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index df233172ded0..027f66ba1baf 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -15,9 +15,14 @@ */ package com.intellij.codeInspection.ui; +import com.intellij.codeInsight.intention.HighPriorityAction; +import com.intellij.codeInsight.intention.LowPriorityAction; +import com.intellij.codeInspection.QuickFix; import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.codeInspection.ui.actions.SuppressActionWrapper; import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.command.WriteCommandAction; @@ -36,15 +41,17 @@ import javax.swing.*; import javax.swing.tree.TreePath; import java.awt.*; import java.awt.event.MouseEvent; -import java.util.ArrayList; +import java.util.*; import java.util.List; -import java.util.Set; import java.util.function.Supplier; /** * @author Dmitry Batkovich */ public class QuickFixToolbar extends JPanel { + private static final int FIX_MAX_NAME_LENGTH = 40; + private static final int MAX_FIX_COUNT = 3; + @NotNull private final Project myProject; public QuickFixToolbar(@NotNull BatchProblemDescriptor descriptor, @@ -101,6 +108,7 @@ public class QuickFixToolbar extends JPanel { final ComboBoxAction action = new ComboBoxAction() { { getTemplatePresentation().setText("Suppress"); + setSmallVariant(false); } @NotNull @@ -111,30 +119,82 @@ public class QuickFixToolbar extends JPanel { return group; } }; - action.setSmallVariant(false); return action.createCustomComponent(action.getTemplatePresentation()); } @NotNull private JPanel createFixPanel(@NotNull final BatchProblemDescriptor descriptor, @NotNull final Project project, Set fixes) { - JPanel fixPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, JBUI.scale(3), JBUI.scale(5))); - for (String fixName : fixes) { - final JButton quickFixButton = new JButton(fixName); - fixPanel.add(quickFixButton); - new ClickListener() { - @Override - public boolean onClick(@NotNull MouseEvent event, int clickCount) { - WriteCommandAction.runWriteCommandAction(myProject, () -> { - descriptor.applyFixes(fixName, project); - }); - setVisible(false); - return true; + final Collection sortedFixes; + if (fixes.size() == 1) { + sortedFixes = fixes; + } + else { + sortedFixes = new TreeSet<>((String fixName1, String fixName2) -> { + final QuickFix fix1 = descriptor.findFixFor(fixName1); + final QuickFix fix2 = descriptor.findFixFor(fixName2); + int rate1 = 0; + if (fix1 instanceof HighPriorityAction) rate1 = -1; + if (fix1 instanceof LowPriorityAction) rate1 = 1; + int rate2 = 0; + if (fix2 instanceof HighPriorityAction) rate2 = -1; + if (fix2 instanceof LowPriorityAction) rate2 = 1; + if (rate1 != rate2) { + return rate1 - rate2; } - }.installOn(quickFixButton); + return fixName1.compareTo(fixName2); + }); + sortedFixes.addAll(fixes); + } + //TODO sort fixes + JPanel fixPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, JBUI.scale(3), JBUI.scale(5))); + if (sortedFixes.size() > 3) { + final ComboBoxAction fixComboBox = new ComboBoxAction() { + { + getTemplatePresentation().setText("Apply quick fixes"); + setSmallVariant(false); + } + + @NotNull + @Override + protected DefaultActionGroup createPopupActionGroup(JComponent button) { + final DefaultActionGroup actionGroup = new DefaultActionGroup(); + for (String fixName : sortedFixes) { + actionGroup.add(new AnAction(fixName) { + @Override + public void actionPerformed(AnActionEvent e) { + applyFixes(descriptor, fixName, project); + } + }); + } + return actionGroup; + } + }; + fixPanel.add(fixComboBox.createCustomComponent(fixComboBox.getTemplatePresentation())); + } + else { + for (String fixName : sortedFixes) { + final JButton quickFixButton = + new JButton(fixName.length() > FIX_MAX_NAME_LENGTH ? (fixName.substring(0, FIX_MAX_NAME_LENGTH) + "...") : fixName); + fixPanel.add(quickFixButton); + new ClickListener() { + @Override + public boolean onClick(@NotNull MouseEvent event, int clickCount) { + applyFixes(descriptor, fixName, project); + setVisible(false); + return true; + } + }.installOn(quickFixButton); + } } return fixPanel; } + private void applyFixes(@NotNull BatchProblemDescriptor descriptor, String fixName, @NotNull Project project) { + WriteCommandAction.runWriteCommandAction(myProject, () -> { + descriptor.applyFixes(fixName, project); + }); + } + private static void fill(@Nullable Couple point, @NotNull Supplier componentSupplier, @NotNull List parent) { From 067378649dd9e1a1d94b6d599f1e876c6f03c0da Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 11 Feb 2016 15:39:32 +0300 Subject: [PATCH 07/84] inspection toolwindow: toolbar is not shown if quick fix is applied --- .../ui/InspectionResultsView.java | 30 +++++++++---------- .../ui/ProblemDescriptionNode.java | 4 ++- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 9bf60f92c0a9..a009d0d69484 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -398,18 +398,18 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren final RefEntity refSelected = refElementNode.getElement(); if (node.isLeaf()) { LOG.assertTrue(problem != null); - showInRightPanel(refSelected, BatchProblemDescriptor.single(problem)); + showInRightPanel(refSelected, BatchProblemDescriptor.single(problem), node.isValid()); } else { - showInRightPanel(refSelected, node.accumulateProblemInfo(new BatchProblemDescriptor(false))); + showInRightPanel(refSelected, node.accumulateProblemInfo(new BatchProblemDescriptor(false)), node.isValid()); } } else if (node instanceof ProblemDescriptionNode) { final ProblemDescriptionNode problemNode = (ProblemDescriptionNode)node; - showInRightPanel(problemNode.getElement(), BatchProblemDescriptor.single(problemNode.getDescriptor())); + showInRightPanel(problemNode.getElement(), BatchProblemDescriptor.single(problemNode.getDescriptor()), node.isValid()); } else if (node instanceof InspectionNode) { - showInRightPanel(null, node.accumulateProblemInfo(new BatchProblemDescriptor(false))); + showInRightPanel(null, node.accumulateProblemInfo(new BatchProblemDescriptor(false)), node.isValid()); } else { mySplitter.setSecondComponent(new JPanel()); @@ -418,23 +418,25 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } } - private void showInRightPanel(final RefEntity refEntity, BatchProblemDescriptor intersector) { + private void showInRightPanel(final RefEntity refEntity, BatchProblemDescriptor descriptor, boolean valid) { //todo use refentity to determine Cursor currentCursor = getCursor(); setCursor(new Cursor(Cursor.WAIT_CURSOR)); - if (intersector != null) { + if (descriptor != null) { final JPanel editorPanel = new JPanel(); editorPanel.setLayout(new BorderLayout()); final PsiElement containingElement = refEntity instanceof RefElement ? ((RefElement)refEntity).getElement() : null; - final QuickFixToolbar toolbar = new QuickFixToolbar(intersector, - myTree.getSelectedToolWrapper(), - myTree.getSelectionPaths(), - myProject, - containingElement); - editorPanel.add(toolbar, BorderLayout.NORTH); - editorPanel.add(createBaseRightComponentFor(containingElement, intersector), BorderLayout.CENTER); + if (valid && descriptor.getProblemCount() > 0) { + editorPanel.add(new QuickFixToolbar(descriptor, + myTree.getSelectedToolWrapper(), + myTree.getSelectionPaths(), + myProject, + containingElement), + BorderLayout.NORTH); + } + editorPanel.add(createBaseRightComponentFor(containingElement, descriptor), BorderLayout.CENTER); mySplitter.setSecondComponent(editorPanel); } setCursor(currentCursor); @@ -443,8 +445,6 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private JComponent createBaseRightComponentFor(PsiElement containingElement, BatchProblemDescriptor descriptor) { final int count = descriptor.getProblemCount(); if (count == 1 || (containingElement != null && !(containingElement instanceof PsiDirectory))) { - final PsiElement element = descriptor.getFirstProblemElement(); - LOG.assertTrue(element != null); final PsiElement referencedElement = containingElement == null ? descriptor.getFirstProblemElement() : containingElement; final PsiFile file = referencedElement.getContainingFile(); final Document document = PsiDocumentManager.getInstance(referencedElement.getProject()).getDocument(file); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java index bf89ddafdf5e..7b4dea8826c5 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java @@ -89,7 +89,9 @@ public class ProblemDescriptionNode extends InspectionTreeNode { @Override public BatchProblemDescriptor accumulateProblemInfo(BatchProblemDescriptor accumulator) { - accumulator.addProblem(getDescriptor()); + if (isValid()) { + accumulator.addProblem(getDescriptor()); + } return accumulator; } From e58c7d528820a384bf23694506325764ee72d56b Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 11 Feb 2016 16:22:03 +0300 Subject: [PATCH 08/84] inspection toolwindow: special panel is shown when root or group node is selected --- .../ui/InspectionResultsView.java | 10 +++- .../ui/InspectionViewNavigationPanel.java | 60 +++++++++++++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionViewNavigationPanel.java diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index a009d0d69484..e7ac82cc889b 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -51,6 +51,7 @@ import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.*; +import com.intellij.ui.components.JBLabel; import com.intellij.usageView.UsageInfo; import com.intellij.usages.impl.UsagePreviewPanel; import com.intellij.util.ConcurrencyUtil; @@ -382,9 +383,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private void syncRightPanel() { if (myTree.getSelectionModel().getSelectionCount() != 1) { - final JLabel multipleSelectionLabel = new JLabel("Select inspection tree node to see problem description"); + final JLabel multipleSelectionLabel = new JBLabel(InspectionViewNavigationPanel.getTitleText(false, false)); multipleSelectionLabel.setVerticalAlignment(SwingConstants.TOP); - multipleSelectionLabel.setBorder(IdeBorderFactory.createEmptyBorder(JBUI.scale(5), JBUI.scale(5), 0, 0)); + multipleSelectionLabel.setBorder(IdeBorderFactory.createEmptyBorder(5, 7, 0, 0)); mySplitter.setSecondComponent(multipleSelectionLabel); } else { @@ -411,8 +412,11 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren else if (node instanceof InspectionNode) { showInRightPanel(null, node.accumulateProblemInfo(new BatchProblemDescriptor(false)), node.isValid()); } + else if (node instanceof InspectionRootNode || node instanceof InspectionGroupNode) { + mySplitter.setSecondComponent(new InspectionViewNavigationPanel(node, myTree)); + } else { - mySplitter.setSecondComponent(new JPanel()); + LOG.error("Unexpected node: " + node.getClass()); } } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionViewNavigationPanel.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionViewNavigationPanel.java new file mode 100644 index 000000000000..4579854165ee --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionViewNavigationPanel.java @@ -0,0 +1,60 @@ +/* + * 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. + */ +package com.intellij.codeInspection.ui; + +import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.labels.LinkLabel; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.tree.TreeUtil; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeNode; +import java.awt.*; + +/** + * @author Dmitry Batkovich + */ +public class InspectionViewNavigationPanel extends JPanel { + public InspectionViewNavigationPanel(InspectionTreeNode node, InspectionTree tree) { + setLayout(new BorderLayout()); + setBorder(IdeBorderFactory.createEmptyBorder(5, 7, 0, 0)); + final String titleLabelText = getTitleText(node instanceof InspectionRootNode, true); + add(new JBLabel(titleLabelText), BorderLayout.NORTH); + final JPanel links = new JPanel(); + links.setLayout(new BoxLayout(links, BoxLayout.Y_AXIS)); + links.add(Box.createVerticalStrut(JBUI.scale(10))); + add(BorderLayout.CENTER, links); + for (int i = 0; i < node.getChildCount(); i++) { + final TreeNode child = node.getChildAt(i); + final LinkLabel link = new LinkLabel(child.toString(), null) { + @Override + public void doClick() { + TreeUtil.selectInTree((DefaultMutableTreeNode)child, true, tree); + } + }; + link.setBorder(IdeBorderFactory.createEmptyBorder(1, 17, 3, 1)); + links.add(link); + } + } + + @NotNull + public static String getTitleText(boolean addGroupWord, boolean addColon) { + return "Select inspection " + (addGroupWord ? "group" : "") + " to see problems" + (addColon ? ":" : "."); + } +} From 68f23e888fff0dbaecc57657ae2b7555abc08153 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 11 Feb 2016 16:26:18 +0300 Subject: [PATCH 09/84] inspection toolwindow: insets are fixed --- .../codeInspection/ui/InspectionNodeInfo.java | 24 +++++++++---------- .../codeInspection/ui/QuickFixToolbar.java | 11 ++++----- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java index 9f33f36868d0..e933be246ff5 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java @@ -27,6 +27,7 @@ import com.intellij.ui.*; import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBScrollPane; import com.intellij.util.Consumer; +import com.intellij.util.ui.JBInsets; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -48,7 +49,7 @@ public class InspectionNodeInfo extends JPanel { public InspectionNodeInfo(final InspectionToolWrapper toolWrapper, Project project) { setLayout(new GridBagLayout()); - setBorder(IdeBorderFactory.createEmptyBorder(new Insets(0, JBUI.scale(3), 0, 0))); + setBorder(IdeBorderFactory.createEmptyBorder(0, 3, 0, 0)); myProject = project; myTitle = new SimpleColoredComponent(); myCurrentProfile = (InspectionProfileImpl)InspectionProjectProfileManager.getInstance(project).getProjectProfileImpl(); @@ -57,14 +58,14 @@ public class InspectionNodeInfo extends JPanel { myButton = new JButton(); add(myTitle, - new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, JBUI.scale(2), 0, 0), + new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new JBInsets(0, 2, 0, 0), 0, 0)); add(new JBLabel(String.valueOf(toolWrapper.loadDescription()), UIUtil.ComponentStyle.SMALL), new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, - new Insets(JBUI.scale(5), JBUI.scale(5), 0, 0), 0, 0)); + new JBInsets(5, 5, 0, 0), 0, 0)); add(myButton, new GridBagConstraints(0, 2, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, - new Insets(JBUI.scale(15), 0, 0, 0), 0, 0)); + new JBInsets(15, 0, 0, 0), 0, 0)); updateEnableButtonText(false); new ClickListener() { @@ -80,15 +81,12 @@ public class InspectionNodeInfo extends JPanel { boolean isEnabled = myCurrentProfile.isToolEnabled(myKey); if (revert) { final boolean isEnabledAsFinal = isEnabled; - DisableInspectionToolAction.modifyAndCommitProjectProfile(new Consumer() { - @Override - public void consume(ModifiableModel model) { - if (isEnabledAsFinal) { - model.disableTool(myKey.getID(), myProject); - } - else { - ((InspectionProfileImpl)model).enableTool(myKey.getID(), myProject); - } + DisableInspectionToolAction.modifyAndCommitProjectProfile(model -> { + if (isEnabledAsFinal) { + model.disableTool(myKey.getID(), myProject); + } + else { + ((InspectionProfileImpl)model).enableTool(myKey.getID(), myProject); } }, myProject); isEnabled = !isEnabled; diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index 027f66ba1baf..51cdc2a9dd91 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -73,7 +73,7 @@ public class QuickFixToolbar extends JPanel { panels.add((JPanel)add(line)); } if (multipleDescriptors) { - panels.get(0).setBorder(IdeBorderFactory.createEmptyBorder(new Insets(JBUI.scale(5), 0, 0, 0))); + panels.get(0).setBorder(IdeBorderFactory.createEmptyBorder(5, 0, 0, 0)); } fill(getBulbPlacement(hasFixes), QuickFixToolbar::createBulbIcon, panels); @@ -89,7 +89,7 @@ public class QuickFixToolbar extends JPanel { new JBLabel((hasFixes ? " Fix " : " ") + problemsCount + " warnings " + (target == null ? "" : ("in " + target.getName()))); Font font = label.getFont(); if (!hasFixes) { - label.setBorder(IdeBorderFactory.createEmptyBorder(new Insets(JBUI.scale(0), JBUI.scale(3), JBUI.scale(6), 0))); + label.setBorder(IdeBorderFactory.createEmptyBorder(0, 3, 6, 0)); } label.setFont(new Font(font.getFontName(), Font.BOLD, font.getSize())); return label; @@ -98,7 +98,7 @@ public class QuickFixToolbar extends JPanel { @NotNull private static JLabel createBulbIcon() { final JLabel label = new JLabel(AllIcons.Actions.IntentionBulb); - label.setBorder(IdeBorderFactory.createEmptyBorder(new Insets(0, JBUI.scale(10), 0, 0))); + label.setBorder(IdeBorderFactory.createEmptyBorder(0, 10, 0, 0)); return label; } @@ -108,7 +108,6 @@ public class QuickFixToolbar extends JPanel { final ComboBoxAction action = new ComboBoxAction() { { getTemplatePresentation().setText("Suppress"); - setSmallVariant(false); } @NotNull @@ -119,6 +118,7 @@ public class QuickFixToolbar extends JPanel { return group; } }; + action.setSmallVariant(false); return action.createCustomComponent(action.getTemplatePresentation()); } @@ -145,9 +145,8 @@ public class QuickFixToolbar extends JPanel { }); sortedFixes.addAll(fixes); } - //TODO sort fixes JPanel fixPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, JBUI.scale(3), JBUI.scale(5))); - if (sortedFixes.size() > 3) { + if (sortedFixes.size() > MAX_FIX_COUNT) { final ComboBoxAction fixComboBox = new ComboBoxAction() { { getTemplatePresentation().setText("Apply quick fixes"); From f00f634a79f20e0b0e0920b40fbbdd94df116556 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 11 Feb 2016 17:39:12 +0300 Subject: [PATCH 10/84] inspection toolwindow: embedded editor tuned --- .../intellij/codeInspection/ui/InspectionResultsView.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index e7ac82cc889b..5e44b88b7dcc 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -455,16 +455,12 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren myPreviewEditor = EditorFactory.getInstance().createEditor(document, myProject, file.getVirtualFile(), true); final EditorSettings settings = myPreviewEditor.getSettings(); settings.setLineNumbersShown(false); - settings.setLineNumbersShown(false); - settings.setWhitespacesShown(false); settings.setLineMarkerAreaShown(false); - settings.setIndentGuidesShown(false); - settings.setFoldingOutlineShown(false); settings.setAdditionalColumnsCount(0); settings.setAdditionalLinesCount(0); + settings.setLeadingWhitespaceShown(true); settings.setRightMarginShown(true); settings.setRightMargin(60); - myPreviewEditor.getCaretModel().moveToOffset(referencedElement.getTextOffset()); myPreviewEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); UsagePreviewPanel From 8631022e201ffeab43ddeafd93d8957eef974c08 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 12 Feb 2016 10:25:52 +0300 Subject: [PATCH 11/84] inspection toolwindow: added separator to "suppress all" actions (in alt+enter popup too) --- .../SuppressIntentionAction.java | 4 +++ .../codeInspection/SuppressQuickFix.java | 2 ++ ...BatchSuppressByNoInspectionCommentFix.java | 5 +++ .../SuppressIntentionActionFromFix.java | 4 +++ .../intention/impl/IntentionListStep.java | 6 +++- .../codeInspection/ui/QuickFixToolbar.java | 36 ++++++++----------- .../ui/actions/SuppressActionWrapper.java | 22 ++++++++++-- .../relaxNG/inspections/BaseInspection.java | 10 ++++++ .../XmlSuppressableInspectionTool.java | 5 +++ 9 files changed, 69 insertions(+), 25 deletions(-) diff --git a/platform/analysis-api/src/com/intellij/codeInspection/SuppressIntentionAction.java b/platform/analysis-api/src/com/intellij/codeInspection/SuppressIntentionAction.java index 9b7551beb33f..bd92a55295a0 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/SuppressIntentionAction.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/SuppressIntentionAction.java @@ -100,6 +100,10 @@ public abstract class SuppressIntentionAction implements Iconable, IntentionActi */ public abstract boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element); + public boolean isSuppressAll() { + return false; + } + @Nullable private static PsiElement getElement(@NotNull Editor editor, @NotNull PsiFile file) { CaretModel caretModel = editor.getCaretModel(); diff --git a/platform/analysis-api/src/com/intellij/codeInspection/SuppressQuickFix.java b/platform/analysis-api/src/com/intellij/codeInspection/SuppressQuickFix.java index e0fff380f57c..6c4d53750775 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/SuppressQuickFix.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/SuppressQuickFix.java @@ -22,4 +22,6 @@ import org.jetbrains.annotations.NotNull; public interface SuppressQuickFix extends LocalQuickFix { SuppressQuickFix[] EMPTY_ARRAY = new SuppressQuickFix[0]; boolean isAvailable(@NotNull final Project project, @NotNull final PsiElement context); + + boolean isSuppressAll(); } diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/actions/AbstractBatchSuppressByNoInspectionCommentFix.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/actions/AbstractBatchSuppressByNoInspectionCommentFix.java index 2572bb617156..56188b949649 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/actions/AbstractBatchSuppressByNoInspectionCommentFix.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/actions/AbstractBatchSuppressByNoInspectionCommentFix.java @@ -106,6 +106,11 @@ public abstract class AbstractBatchSuppressByNoInspectionCommentFix implements C invoke(project, element); } + @Override + public boolean isSuppressAll() { + return SuppressionUtil.ALL.equals(myID); + } + protected final void replaceSuppressionComment(@NotNull final PsiElement comment) { SuppressionUtil.replaceSuppressionComment(comment, myID, myReplaceOtherSuppressionIds, getCommentLanguage(comment)); } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/SuppressIntentionActionFromFix.java b/platform/analysis-impl/src/com/intellij/codeInspection/SuppressIntentionActionFromFix.java index 330baea5d08d..e3274879aab6 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/SuppressIntentionActionFromFix.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/SuppressIntentionActionFromFix.java @@ -85,4 +85,8 @@ public class SuppressIntentionActionFromFix extends SuppressIntentionAction { public String getFamilyName() { return myFix.getFamilyName(); } + + public boolean isSuppressAll() { + return myFix.isSuppressAll(); + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionListStep.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionListStep.java index 2c85d06fbf74..916f730b555b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionListStep.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionListStep.java @@ -377,9 +377,13 @@ public class IntentionListStep implements ListPopupStep getLabel(hasFixes, (PsiNamedElement)containingElement, descriptor.getProblemCount()), panels); fill(getFixesPlacement(hasFixes, multipleDescriptors), () -> createFixPanel(descriptor, project, fixes), panels); - fill(getSuppressPlacement(hasFixes, multipleDescriptors), () -> createSuppressionCombo(toolWrapper, paths, project), panels); + fill(getSuppressPlacement(multipleDescriptors), () -> createSuppressionCombo(toolWrapper, paths, project), panels); } @NotNull @@ -194,36 +193,29 @@ public class QuickFixToolbar extends JPanel { }); } - private static void fill(@Nullable Couple point, + private static void fill(int row, @NotNull Supplier componentSupplier, @NotNull List parent) { - if (point == null) { + if (row == -1) { return; } - final int y = point.getSecond(); - final JPanel row = parent.get(y); - row.add(componentSupplier.get()); + final JPanel rowPanel = parent.get(row); + rowPanel.add(componentSupplier.get()); } - @NotNull - private static Couple getSuppressPlacement(boolean hasQuickFixes, boolean multipleDescriptors) { - return hasQuickFixes - ? multipleDescriptors ? Couple.of(1, 1) : Couple.of(2, 0) - : Couple.of(0, multipleDescriptors ? 1 : 0); + private static int getSuppressPlacement(boolean multipleDescriptors) { + return multipleDescriptors ? 1 : 0; } - @Nullable - private static Couple getFixesPlacement(boolean hasQuickFixes, boolean multipleDescriptors) { - return hasQuickFixes ? multipleDescriptors ? Couple.of(0, 1) : Couple.of(1, 0) : null; + private static int getFixesPlacement(boolean hasQuickFixes, boolean multipleDescriptors) { + return hasQuickFixes ? multipleDescriptors ? 1 : 0 : -1; } - @Nullable - private static Couple getDescriptionLabelPlacement(boolean hasQuickFixes, boolean multipleDescriptors) { - return multipleDescriptors ? Couple.of(hasQuickFixes ? 1 : 0, 0) : null; + private static int getDescriptionLabelPlacement(boolean multipleDescriptors) { + return multipleDescriptors ? 0 : -1; } - @Nullable - private static Couple getBulbPlacement(boolean hasQuickFixes) { - return hasQuickFixes ? Couple.of(0, 0) : null; + private static int getBulbPlacement(boolean hasQuickFixes) { + return hasQuickFixes ? 0 : -1; } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/SuppressActionWrapper.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/SuppressActionWrapper.java index 20db55e49ae9..8e5943bcb944 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/SuppressActionWrapper.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/SuppressActionWrapper.java @@ -32,6 +32,7 @@ import com.intellij.codeInspection.ui.RefElementNode; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Separator; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; @@ -49,6 +50,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; +import java.util.Arrays; +import java.util.Comparator; import java.util.Set; public class SuppressActionWrapper extends ActionGroup { @@ -83,14 +86,25 @@ public class SuppressActionWrapper extends ActionGroup { @Override @NotNull - public SuppressTreeAction[] getChildren(@Nullable final AnActionEvent e) { + public AnAction[] getChildren(@Nullable final AnActionEvent e) { final SuppressIntentionAction[] suppressActions = InspectionManagerEx.getSuppressActions(myToolWrapper); if (suppressActions == null || suppressActions.length == 0) return new SuppressTreeAction[0]; - final SuppressTreeAction[] actions = new SuppressTreeAction[suppressActions.length]; + final AnAction[] actions = new AnAction[suppressActions.length + 1]; for (int i = 0; i < suppressActions.length; i++) { final SuppressIntentionAction suppressAction = suppressActions[i]; actions[i] = new SuppressTreeAction(suppressAction); } + actions[suppressActions.length] = Separator.getInstance(); + Arrays.sort(actions, new Comparator() { + @Override + public int compare(AnAction a1, AnAction a2) { + return getWeight(a1) - getWeight(a2); + } + + public int getWeight(AnAction a) { + return a instanceof Separator ? 0 : ((SuppressTreeAction)a).isSuppressAll() ? 1 : -1; + } + }); return actions; } @@ -219,5 +233,9 @@ public class SuppressActionWrapper extends ActionGroup { } return false; } + + public boolean isSuppressAll() { + return mySuppressAction.isSuppressAll(); + } } } diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/inspections/BaseInspection.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/inspections/BaseInspection.java index 03916fce7322..df6768e5f5f3 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/inspections/BaseInspection.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/inspections/BaseInspection.java @@ -140,6 +140,11 @@ public abstract class BaseInspection extends XmlSuppressableInspectionTool { public String getFamilyName() { return action.getFamilyName(); } + + @Override + public boolean isSuppressAll() { + return action.isSuppressAll(); + } }; } }, SuppressQuickFix.EMPTY_ARRAY); @@ -222,5 +227,10 @@ public abstract class BaseInspection extends XmlSuppressableInspectionTool { } protected abstract PsiElement getTarget(PsiElement element); + + @Override + public boolean isSuppressAll() { + return false; + } } } diff --git a/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java b/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java index a78c969b0424..34c670b74dfa 100644 --- a/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java +++ b/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java @@ -82,6 +82,11 @@ public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool public void setShouldBeAppliedToInjectionHost(@NotNull ThreeState shouldBeAppliedToInjectionHost) { myShouldBeAppliedToInjectionHost = shouldBeAppliedToInjectionHost; } + + @Override + public boolean isSuppressAll() { + return false; + } } public static class SuppressTagStatic extends XmlSuppressFix { From fb5494a0008516bb6bf3e7f7d4ae7e7796611d2a Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 12 Feb 2016 15:09:18 +0300 Subject: [PATCH 12/84] inspection toolwindow: simplify suppression action group code --- .../com/intellij/codeInspection/ui/QuickFixToolbar.java | 7 +++---- .../intellij/openapi/actionSystem/ex/ComboBoxAction.java | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index 5928c1fe6a3e..49b34bc4f44d 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -21,6 +21,7 @@ import com.intellij.codeInspection.QuickFix; import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.codeInspection.ui.actions.SuppressActionWrapper; import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; @@ -111,10 +112,8 @@ public class QuickFixToolbar extends JPanel { @NotNull @Override - protected DefaultActionGroup createPopupActionGroup(JComponent button) { - final DefaultActionGroup group = new DefaultActionGroup(); - group.addAll(new SuppressActionWrapper(project, toolWrapper, paths).getChildren(null)); - return group; + protected ActionGroup createPopupActionGroup(JComponent button) { + return new SuppressActionWrapper(project, toolWrapper, paths); } }; action.setSmallVariant(false); diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java index ddd7d1eedc5f..5342866e60f5 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java @@ -81,7 +81,7 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent DataContext context = e.getDataContext(); Project project = e.getProject(); if (project == null) return; - DefaultActionGroup group = createPopupActionGroup(button); + ActionGroup group = createPopupActionGroup(button); ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup( myPopupTitle, group, context, false, shouldShowDisabledActions(), false, null, getMaxRows(), getPreselectCondition()); popup.setMinimumSize(new Dimension(getMinWidth(), getMinHeight())); @@ -124,7 +124,7 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent @NotNull - protected abstract DefaultActionGroup createPopupActionGroup(JComponent button); + protected abstract ActionGroup createPopupActionGroup(JComponent button); protected int getMaxRows() { return 30; @@ -277,7 +277,7 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent } protected JBPopup createPopup(Runnable onDispose) { - DefaultActionGroup group = createPopupActionGroup(this); + ActionGroup group = createPopupActionGroup(this); DataContext context = getDataContext(); ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup( From aa5c31a0139b696ee0945f862bf4ca57e97bdf76 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 12 Feb 2016 15:11:50 +0300 Subject: [PATCH 13/84] inspection toolwindow: wrap cursor code in try-finally --- .../ui/InspectionResultsView.java | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 5e44b88b7dcc..ec5bb854351d 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -423,27 +423,30 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } private void showInRightPanel(final RefEntity refEntity, BatchProblemDescriptor descriptor, boolean valid) { - //todo use refentity to determine Cursor currentCursor = getCursor(); - setCursor(new Cursor(Cursor.WAIT_CURSOR)); + try { + setCursor(new Cursor(Cursor.WAIT_CURSOR)); - if (descriptor != null) { - final JPanel editorPanel = new JPanel(); - editorPanel.setLayout(new BorderLayout()); + if (descriptor != null) { + final JPanel editorPanel = new JPanel(); + editorPanel.setLayout(new BorderLayout()); - final PsiElement containingElement = refEntity instanceof RefElement ? ((RefElement)refEntity).getElement() : null; - if (valid && descriptor.getProblemCount() > 0) { - editorPanel.add(new QuickFixToolbar(descriptor, - myTree.getSelectedToolWrapper(), - myTree.getSelectionPaths(), - myProject, - containingElement), - BorderLayout.NORTH); + final PsiElement containingElement = refEntity instanceof RefElement ? ((RefElement)refEntity).getElement() : null; + if (valid && descriptor.getProblemCount() > 0) { + editorPanel.add(new QuickFixToolbar(descriptor, + myTree.getSelectedToolWrapper(), + myTree.getSelectionPaths(), + myProject, + containingElement), + BorderLayout.NORTH); + } + editorPanel.add(createBaseRightComponentFor(containingElement, descriptor), BorderLayout.CENTER); + mySplitter.setSecondComponent(editorPanel); } - editorPanel.add(createBaseRightComponentFor(containingElement, descriptor), BorderLayout.CENTER); - mySplitter.setSecondComponent(editorPanel); } - setCursor(currentCursor); + finally { + setCursor(currentCursor); + } } private JComponent createBaseRightComponentFor(PsiElement containingElement, BatchProblemDescriptor descriptor) { From 165a1004512cd205b6d2bb10eaac78a3058ab99e Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 12 Feb 2016 16:43:39 +0300 Subject: [PATCH 14/84] inspection toolwindow: quick fix buttons on the right rewritten to action-based --- .../ui/BatchProblemDescriptor.java | 37 ++++----- .../codeInspection/ui/QuickFixToolbar.java | 83 ++++++++++--------- 2 files changed, 62 insertions(+), 58 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java index 5729cabb0d9d..beafceabedc6 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java @@ -16,6 +16,7 @@ package com.intellij.codeInspection.ui; import com.intellij.codeInspection.CommonProblemDescriptor; +import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptorBase; import com.intellij.codeInspection.QuickFix; import com.intellij.openapi.diagnostic.Logger; @@ -23,11 +24,10 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import java.util.*; /** * @author Dmitry Batkovich @@ -104,28 +104,23 @@ public class BatchProblemDescriptor { return null; } - public Set getQuickFixNames() { + @NotNull + public List getQuickFixRepresentatives() { LOG.assertTrue(!myOnlyCount); - return myMap.keySet(); - } - - public void applyFixes(final String name, final Project project) { - LOG.assertTrue(!myOnlyCount); - for (CommonProblemDescriptor descriptor : myMap.get(name)) { - final QuickFix[] fixes = descriptor.getFixes(); - LOG.assertTrue(fixes != null); - for (QuickFix fix : fixes) { - if (name.equals(fix.getName())) { - //noinspection unchecked - fix.applyFix(project, descriptor); + List result = new ArrayList<>(myMap.size()); + for (Map.Entry> e : myMap.entrySet()) { + final String fixName = e.getKey(); + final Collection descriptors = e.getValue(); + final CommonProblemDescriptor representative = ContainerUtil.getFirstItem(descriptors); + LOG.assertTrue(representative != null); + for (QuickFix fix : representative.getFixes()) { + if (fix.getName().equals(fixName)) { + result.add(fix); + break; } } } - } - - public QuickFix findFixFor(String name) { - LOG.assertTrue(!myOnlyCount); - return ContainerUtil.getFirstItem(myMap.get(name)).getFixes()[0]; + return result; } public boolean isIntersectionTrivial() { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index 49b34bc4f44d..2fd0e0623395 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -19,14 +19,16 @@ import com.intellij.codeInsight.intention.HighPriorityAction; import com.intellij.codeInsight.intention.LowPriorityAction; import com.intellij.codeInspection.QuickFix; import com.intellij.codeInspection.ex.InspectionToolWrapper; +import com.intellij.codeInspection.ex.LocalQuickFixWrapper; import com.intellij.codeInspection.ui.actions.SuppressActionWrapper; import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.ActionGroup; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; -import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.actionSystem.ex.CustomComponentAction; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNamedElement; @@ -41,8 +43,10 @@ import javax.swing.*; import javax.swing.tree.TreePath; import java.awt.*; import java.awt.event.MouseEvent; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.TreeSet; import java.util.function.Supplier; /** @@ -61,8 +65,8 @@ public class QuickFixToolbar extends JPanel { @Nullable PsiElement containingElement) { myProject = project; - final Set fixes = descriptor.getQuickFixNames(); - final boolean hasFixes = fixes != null && !fixes.isEmpty(); + final List fixes = descriptor.getQuickFixRepresentatives(); + final boolean hasFixes = !fixes.isEmpty(); final boolean multipleDescriptors = descriptor.getProblemCount() > 1; setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); @@ -79,7 +83,7 @@ public class QuickFixToolbar extends JPanel { fill(getBulbPlacement(hasFixes), QuickFixToolbar::createBulbIcon, panels); fill(getDescriptionLabelPlacement(multipleDescriptors), () -> getLabel(hasFixes, (PsiNamedElement)containingElement, descriptor.getProblemCount()), panels); - fill(getFixesPlacement(hasFixes, multipleDescriptors), () -> createFixPanel(descriptor, project, fixes), panels); + fill(getFixesPlacement(hasFixes, multipleDescriptors), () -> createFixPanel(fixes, toolWrapper), panels); fill(getSuppressPlacement(multipleDescriptors), () -> createSuppressionCombo(toolWrapper, paths, project), panels); } @@ -121,15 +125,14 @@ public class QuickFixToolbar extends JPanel { } @NotNull - private JPanel createFixPanel(@NotNull final BatchProblemDescriptor descriptor, @NotNull final Project project, Set fixes) { - final Collection sortedFixes; + private JPanel createFixPanel(List fixes, + InspectionToolWrapper toolWrapper) { + final Collection sortedFixes; if (fixes.size() == 1) { sortedFixes = fixes; } else { - sortedFixes = new TreeSet<>((String fixName1, String fixName2) -> { - final QuickFix fix1 = descriptor.findFixFor(fixName1); - final QuickFix fix2 = descriptor.findFixFor(fixName2); + sortedFixes = new TreeSet<>((fix1, fix2) -> { int rate1 = 0; if (fix1 instanceof HighPriorityAction) rate1 = -1; if (fix1 instanceof LowPriorityAction) rate1 = 1; @@ -139,7 +142,7 @@ public class QuickFixToolbar extends JPanel { if (rate1 != rate2) { return rate1 - rate2; } - return fixName1.compareTo(fixName2); + return fix1.getName().compareTo(fix2.getName()); }); sortedFixes.addAll(fixes); } @@ -155,13 +158,8 @@ public class QuickFixToolbar extends JPanel { @Override protected DefaultActionGroup createPopupActionGroup(JComponent button) { final DefaultActionGroup actionGroup = new DefaultActionGroup(); - for (String fixName : sortedFixes) { - actionGroup.add(new AnAction(fixName) { - @Override - public void actionPerformed(AnActionEvent e) { - applyFixes(descriptor, fixName, project); - } - }); + for (QuickFix fix : sortedFixes) { + actionGroup.add(new LocalQuickFixWrapper(fix, toolWrapper)); } return actionGroup; } @@ -169,29 +167,13 @@ public class QuickFixToolbar extends JPanel { fixPanel.add(fixComboBox.createCustomComponent(fixComboBox.getTemplatePresentation())); } else { - for (String fixName : sortedFixes) { - final JButton quickFixButton = - new JButton(fixName.length() > FIX_MAX_NAME_LENGTH ? (fixName.substring(0, FIX_MAX_NAME_LENGTH) + "...") : fixName); - fixPanel.add(quickFixButton); - new ClickListener() { - @Override - public boolean onClick(@NotNull MouseEvent event, int clickCount) { - applyFixes(descriptor, fixName, project); - setVisible(false); - return true; - } - }.installOn(quickFixButton); + for (QuickFix fix : sortedFixes) { + fixPanel.add(createQuickFixButton(fix, toolWrapper)); } } return fixPanel; } - private void applyFixes(@NotNull BatchProblemDescriptor descriptor, String fixName, @NotNull Project project) { - WriteCommandAction.runWriteCommandAction(myProject, () -> { - descriptor.applyFixes(fixName, project); - }); - } - private static void fill(int row, @NotNull Supplier componentSupplier, @NotNull List parent) { @@ -217,4 +199,31 @@ public class QuickFixToolbar extends JPanel { private static int getBulbPlacement(boolean hasQuickFixes) { return hasQuickFixes ? 0 : -1; } + + private static JComponent createQuickFixButton(@NotNull QuickFix fix, @NotNull InspectionToolWrapper toolWrapper) { + final MyCustomComponentLocalQuickFixWrapper action = new MyCustomComponentLocalQuickFixWrapper(fix, toolWrapper); + return action.createCustomComponent(action.getTemplatePresentation()); + } + + private static class MyCustomComponentLocalQuickFixWrapper extends LocalQuickFixWrapper implements CustomComponentAction { + public MyCustomComponentLocalQuickFixWrapper(@NotNull QuickFix fix, @NotNull InspectionToolWrapper toolWrapper) { + super(fix, toolWrapper); + } + + @Override + public JComponent createCustomComponent(Presentation presentation) { + final JButton button = new JButton(presentation.getText()); + new ClickListener() { + @Override + public boolean onClick(@NotNull MouseEvent event, int clickCount) { + actionPerformed(AnActionEvent.createFromAnAction(MyCustomComponentLocalQuickFixWrapper.this, + event, + "LOCAL_QUICK_FIX_WRAPPER_PANEL", + DataManager.getInstance().getDataContext(button))); + return true; + } + }.installOn(button); + return button; + } + } } From 2c36d843726e4fbd5de34ca867e61ba3f7ccfb4a Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 12 Feb 2016 16:44:41 +0300 Subject: [PATCH 15/84] inspection toolwindow: cleanup --- .../com/intellij/codeInspection/ui/QuickFixToolbar.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index 2fd0e0623395..d7261d14b831 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -53,8 +53,7 @@ import java.util.function.Supplier; * @author Dmitry Batkovich */ public class QuickFixToolbar extends JPanel { - private static final int FIX_MAX_NAME_LENGTH = 40; - private static final int MAX_FIX_COUNT = 3; + private static final int MAX_FIX_COUNT = 2; @NotNull private final Project myProject; @@ -125,8 +124,8 @@ public class QuickFixToolbar extends JPanel { } @NotNull - private JPanel createFixPanel(List fixes, - InspectionToolWrapper toolWrapper) { + private static JPanel createFixPanel(List fixes, + InspectionToolWrapper toolWrapper) { final Collection sortedFixes; if (fixes.size() == 1) { sortedFixes = fixes; From 09079ea6ae21f923cc5cd05f8ec8d70ed101a9a3 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 12 Feb 2016 17:12:11 +0300 Subject: [PATCH 16/84] inspection toolwindow: disposed editor call fixed --- .../src/com/intellij/usages/impl/UsagePreviewPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java b/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java index 0a8ebc218f55..64f968b9d60e 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java @@ -122,7 +122,7 @@ public class UsagePreviewPanel extends UsageContextPanelBase { public void run() { if (project.isDisposed()) return; //noinspection ConstantConditions - if (editor1 == editor) { + if (editor1 == editor && !editor.isDisposed()) { doHighlight(infos, editor, project); } } From 639bd27acb5dd0fa5d7ba61e3814db08eb3c09cf Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Sun, 14 Feb 2016 21:24:24 +0300 Subject: [PATCH 17/84] ComboBoxAction looks bad under mac intellij laf in large variant --- .../com/intellij/openapi/actionSystem/ex/ComboBoxAction.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java index 5342866e60f5..db8c5039514f 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java @@ -152,7 +152,9 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent setModel(new MyButtonModel()); setHorizontalAlignment(LEFT); setFocusable(false); - putClientProperty("styleCombo", Boolean.TRUE); + if (isSmallVariant()) { + putClientProperty("styleCombo", Boolean.TRUE); + } Insets margins = getMargin(); setMargin(JBUI.insets(margins.top, 2, margins.bottom, 2)); if (isSmallVariant()) { @@ -410,7 +412,6 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent final Dimension size = getSize(); if (SystemInfo.isMac && UIUtil.isUnderIntelliJLaF()) { - putClientProperty("styleCombo", Boolean.TRUE); super.paint(g); } else { UISettings.setupAntialiasing(g); From cee870f5c59aeadbd080f40aba9a528db0f80e06 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Sun, 14 Feb 2016 21:49:59 +0300 Subject: [PATCH 18/84] inspection tool window: next/prev occurrence action is shown --- .../ui/BatchProblemDescriptor.java | 21 ++- .../ui/InspectionResultsView.java | 24 ++-- .../codeInspection/ui/InspectionTree.java | 18 +-- .../codeInspection/ui/QuickFixToolbar.java | 24 ++-- .../ui/actions/SuppressActionWrapper.java | 2 +- .../GoToSubsequentOccurrenceAction.java | 125 ++++++++++++++++++ 6 files changed, 174 insertions(+), 40 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java index beafceabedc6..5114807f04c1 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java @@ -36,7 +36,7 @@ public class BatchProblemDescriptor { private final static Logger LOG = Logger.getInstance(BatchProblemDescriptor.class); private MultiMap myMap = null; - private final List myDescriptors = new ArrayList<>(); + private final LinkedHashSet myDescriptors = new LinkedHashSet<>(); private final boolean myOnlyCount; public BatchProblemDescriptor(boolean count) { @@ -88,6 +88,17 @@ public class BatchProblemDescriptor { return intersector; } + public PsiElement getProblemElementIfOnlyOne() { + if (myDescriptors.size() != 1) { + return null; + } + CommonProblemDescriptor descriptor = myDescriptors.iterator().next(); + if (descriptor instanceof ProblemDescriptorBase) { + return ((ProblemDescriptorBase)descriptor).getPsiElement(); + } + return null; + } + public int getProblemCount() { return myDescriptors.size(); } @@ -113,7 +124,9 @@ public class BatchProblemDescriptor { final Collection descriptors = e.getValue(); final CommonProblemDescriptor representative = ContainerUtil.getFirstItem(descriptors); LOG.assertTrue(representative != null); - for (QuickFix fix : representative.getFixes()) { + QuickFix[] fixes = representative.getFixes(); + LOG.assertTrue(fixes != null); + for (QuickFix fix : fixes) { if (fix.getName().equals(fixName)) { result.add(fix); break; @@ -127,4 +140,8 @@ public class BatchProblemDescriptor { LOG.assertTrue(!myOnlyCount); return myMap != null && myMap.isEmpty(); } + + public List getDescriptors() { + return new ArrayList<>(myDescriptors); + } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index ec5bb854351d..a2efd9c01ab5 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -58,7 +58,6 @@ import com.intellij.util.ConcurrencyUtil; import com.intellij.util.EditSourceOnDoubleClickHandler; import com.intellij.util.OpenSourceUtil; import com.intellij.util.containers.*; -import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NonNls; @@ -82,6 +81,7 @@ import java.util.*; import java.util.HashSet; import java.util.List; import java.util.concurrent.ConcurrentMap; +import java.util.stream.Collectors; /** * @author max @@ -426,21 +426,23 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren Cursor currentCursor = getCursor(); try { setCursor(new Cursor(Cursor.WAIT_CURSOR)); - if (descriptor != null) { final JPanel editorPanel = new JPanel(); editorPanel.setLayout(new BorderLayout()); - - final PsiElement containingElement = refEntity instanceof RefElement ? ((RefElement)refEntity).getElement() : null; + PsiElement containingElement = descriptor.getProblemElementIfOnlyOne(); + if (containingElement == null && refEntity instanceof RefElement) { + containingElement = ((RefElement)refEntity).getElement(); + } + editorPanel.add(createBaseRightComponentFor(containingElement, descriptor), BorderLayout.CENTER); if (valid && descriptor.getProblemCount() > 0) { editorPanel.add(new QuickFixToolbar(descriptor, myTree.getSelectedToolWrapper(), - myTree.getSelectionPaths(), + myTree.getSelectionPaths()[0], myProject, + myPreviewEditor, containingElement), BorderLayout.NORTH); } - editorPanel.add(createBaseRightComponentFor(containingElement, descriptor), BorderLayout.CENTER); mySplitter.setSecondComponent(editorPanel); } } @@ -452,7 +454,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private JComponent createBaseRightComponentFor(PsiElement containingElement, BatchProblemDescriptor descriptor) { final int count = descriptor.getProblemCount(); if (count == 1 || (containingElement != null && !(containingElement instanceof PsiDirectory))) { - final PsiElement referencedElement = containingElement == null ? descriptor.getFirstProblemElement() : containingElement; + final PsiElement referencedElement = descriptor.getFirstProblemElement(); final PsiFile file = referencedElement.getContainingFile(); final Document document = PsiDocumentManager.getInstance(referencedElement.getProject()).getDocument(file); myPreviewEditor = EditorFactory.getInstance().createEditor(document, myProject, file.getVirtualFile(), true); @@ -464,11 +466,13 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren settings.setLeadingWhitespaceShown(true); settings.setRightMarginShown(true); settings.setRightMargin(60); - myPreviewEditor.getCaretModel().moveToOffset(referencedElement.getTextOffset()); - myPreviewEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + if (count != 1) { + myPreviewEditor.getCaretModel().moveToOffset(referencedElement.getTextOffset()); + myPreviewEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + } UsagePreviewPanel .highlight(containingElement == null - ? Collections.singletonList(new UsageInfo(referencedElement)) + ? Collections.emptyList() : getElementToHighlight(containingElement), myPreviewEditor, myProject); return myPreviewEditor.getComponent(); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java index 474c78b70e41..ad1e87766b07 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java @@ -164,24 +164,14 @@ public class InspectionTree extends Tree { } public CommonProblemDescriptor[] getSelectedDescriptors() { - final InspectionToolWrapper toolWrapper = getSelectedToolWrapper(); if (getSelectionCount() == 0) return EMPTY_DESCRIPTORS; final TreePath[] paths = getSelectionPaths(); - final LinkedHashSet descriptors = new LinkedHashSet(); + if (paths == null) return EMPTY_DESCRIPTORS; + BatchProblemDescriptor accumulator = new BatchProblemDescriptor(true); for (TreePath path : paths) { - Object node = path.getLastPathComponent(); - traverseDescriptors((InspectionTreeNode)node, descriptors); - } - return descriptors.toArray(new CommonProblemDescriptor[descriptors.size()]); - } - - private static void traverseDescriptors(InspectionTreeNode node, LinkedHashSet descriptors){ - if (node instanceof ProblemDescriptionNode) { - descriptors.add(((ProblemDescriptionNode)node).getDescriptor()); - } - for(int i = node.getChildCount() - 1; i >= 0; i--){ - traverseDescriptors((InspectionTreeNode)node.getChildAt(i), descriptors); + ((InspectionTreeNode)path.getLastPathComponent()).accumulateProblemInfo(accumulator); } + return accumulator.getDescriptors().toArray(new CommonProblemDescriptor[accumulator.getProblemCount()]); } private void nodeStructureChanged(InspectionTreeNode node) { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index d7261d14b831..ec3a73031c1d 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -21,14 +21,13 @@ import com.intellij.codeInspection.QuickFix; import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.codeInspection.ex.LocalQuickFixWrapper; import com.intellij.codeInspection.ui.actions.SuppressActionWrapper; +import com.intellij.codeInspection.ui.actions.occurrences.GoToSubsequentOccurrenceAction; import com.intellij.icons.AllIcons; import com.intellij.ide.DataManager; -import com.intellij.openapi.actionSystem.ActionGroup; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.actionSystem.ex.CustomComponentAction; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNamedElement; @@ -55,15 +54,12 @@ import java.util.function.Supplier; public class QuickFixToolbar extends JPanel { private static final int MAX_FIX_COUNT = 2; - @NotNull private final Project myProject; - public QuickFixToolbar(@NotNull BatchProblemDescriptor descriptor, @NotNull InspectionToolWrapper toolWrapper, - @NotNull TreePath[] paths, + @NotNull TreePath path, @NotNull Project project, + @Nullable Editor editor, @Nullable PsiElement containingElement) { - - myProject = project; final List fixes = descriptor.getQuickFixRepresentatives(); final boolean hasFixes = !fixes.isEmpty(); final boolean multipleDescriptors = descriptor.getProblemCount() > 1; @@ -83,11 +79,13 @@ public class QuickFixToolbar extends JPanel { fill(getDescriptionLabelPlacement(multipleDescriptors), () -> getLabel(hasFixes, (PsiNamedElement)containingElement, descriptor.getProblemCount()), panels); fill(getFixesPlacement(hasFixes, multipleDescriptors), () -> createFixPanel(fixes, toolWrapper), panels); - fill(getSuppressPlacement(multipleDescriptors), () -> createSuppressionCombo(toolWrapper, paths, project), panels); + fill(getSuppressPlacement(multipleDescriptors), () -> createSuppressionCombo(toolWrapper, path, project), panels); + fill(multipleDescriptors && editor != null ? 1 : -1, () -> ActionManager.getInstance().createActionToolbar("", GoToSubsequentOccurrenceAction.createNextPreviousActions( + editor, descriptor.getDescriptors()), true).getComponent(), panels); } @NotNull - private JLabel getLabel(boolean hasFixes, PsiNamedElement target, int problemsCount) { + private static JLabel getLabel(boolean hasFixes, PsiNamedElement target, int problemsCount) { final JBLabel label = new JBLabel((hasFixes ? " Fix " : " ") + problemsCount + " warnings " + (target == null ? "" : ("in " + target.getName()))); Font font = label.getFont(); @@ -106,7 +104,7 @@ public class QuickFixToolbar extends JPanel { } private static JComponent createSuppressionCombo(@NotNull final InspectionToolWrapper toolWrapper, - @NotNull final TreePath[] paths, + @NotNull final TreePath path, @NotNull final Project project) { final ComboBoxAction action = new ComboBoxAction() { { @@ -116,7 +114,7 @@ public class QuickFixToolbar extends JPanel { @NotNull @Override protected ActionGroup createPopupActionGroup(JComponent button) { - return new SuppressActionWrapper(project, toolWrapper, paths); + return new SuppressActionWrapper(project, toolWrapper, path); } }; action.setSmallVariant(false); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/SuppressActionWrapper.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/SuppressActionWrapper.java index 8e5943bcb944..3b0399299785 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/SuppressActionWrapper.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/SuppressActionWrapper.java @@ -63,7 +63,7 @@ public class SuppressActionWrapper extends ActionGroup { public SuppressActionWrapper(@NotNull final Project project, @NotNull final InspectionToolWrapper toolWrapper, - @NotNull final TreePath[] paths) { + @NotNull final TreePath... paths) { super(InspectionsBundle.message("suppress.inspection.problem"), false); myProject = project; myManager = (InspectionManagerEx)InspectionManager.getInstance(myProject); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java new file mode 100644 index 000000000000..5e979cc8d6f9 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java @@ -0,0 +1,125 @@ +/* + * 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. + */ +package com.intellij.codeInspection.ui.actions.occurrences; + +import com.intellij.codeInspection.CommonProblemDescriptor; +import com.intellij.codeInspection.ProblemDescriptorBase; +import com.intellij.codeInspection.reference.RefElement; +import com.intellij.codeInspection.reference.RefEntity; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.ActionGroup; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Dmitry Batkovich + */ +public class GoToSubsequentOccurrenceAction extends AnAction { + private final boolean myNext; + private OccurrencesManager myManager; + + private GoToSubsequentOccurrenceAction(boolean next, OccurrencesManager manager) { + myNext = next; + myManager = manager; + getTemplatePresentation().setIcon(next ? AllIcons.Actions.NextOccurence : AllIcons.Actions.PreviousOccurence); + getTemplatePresentation().setDescription("Navigate to the " + (next ? "Next" : "Previous") + " Occurrence"); + } + + @Override + public void update(AnActionEvent e) { + e.getPresentation().setEnabledAndVisible(myManager.hasValidSubsequent()); + } + + @Override + public void actionPerformed(AnActionEvent e) { + myManager.selectSubsequent(myNext); + } + + public static ActionGroup createNextPreviousActions(@NotNull Editor editor, @NotNull List descriptors) { + OccurrencesManager manager = new OccurrencesManager(editor, descriptors); + return new DefaultActionGroup(new GoToSubsequentOccurrenceAction(false, manager), new GoToSubsequentOccurrenceAction(true, manager)); + } + + private static class OccurrencesManager { + private final Editor myEditor; + private final List myChildren; + + private int mySelected = -1; + + private OccurrencesManager(@NotNull Editor editor, @NotNull List descriptors) { + myEditor = editor; + myChildren = descriptors.stream() + .filter(d -> d instanceof ProblemDescriptorBase) + .map(d -> (ProblemDescriptorBase) d) + .filter(d -> { + PsiElement element = d.getPsiElement(); + return element != null && element.isValid(); + }) + .sorted((o1, o2) -> o1.getPsiElement().getTextOffset() - o2.getPsiElement().getTextOffset()) + .collect(Collectors.toList()); + selectSubsequent(true); + } + + public void selectSubsequent(boolean next) { + int subsequentIdz = mySelected; + while (true) { + subsequentIdz += next ? 1 : -1; + subsequentIdz += myChildren.size(); + subsequentIdz %= myChildren.size(); + if (mySelected == subsequentIdz) { + throw new IllegalStateException("Selection is unavailable"); + } + ProblemDescriptorBase descriptorBase = myChildren.get(subsequentIdz); + if (descriptorBase.getPsiElement().isValid()) { + mySelected = subsequentIdz; + PsiElement toSelect = descriptorBase.getPsiElement(); + myEditor.getCaretModel().moveToOffset(toSelect.getTextOffset()); + myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + myEditor.getSelectionModel().setSelection(toSelect.getTextRange().getStartOffset(), toSelect.getTextRange().getEndOffset()); + return; + } + } + } + + public boolean hasValidSubsequent() { + int subsequentIdz = mySelected; + while (true) { + subsequentIdz += 1 + myChildren.size(); + subsequentIdz %= myChildren.size(); + if (mySelected == subsequentIdz) { + return false; + } + ProblemDescriptorBase descriptorBase = myChildren.get(subsequentIdz); + if (descriptorBase.getPsiElement().isValid()) { + return true; + } + } + } + } +} From d2a545998891c5ff2643b3cbdeb0adc5a68d14b5 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 15 Feb 2016 11:13:17 +0300 Subject: [PATCH 19/84] inspection tool window: unnessecary class removed --- .../codeInspection/ex/QuickFixAction.java | 1 + .../ui/BatchProblemDescriptor.java | 147 ------------------ .../codeInspection/ui/InspectionNode.java | 2 +- .../ui/InspectionResultsView.java | 67 ++++---- .../codeInspection/ui/InspectionTree.java | 21 ++- .../codeInspection/ui/InspectionTreeNode.java | 7 +- .../ui/ProblemDescriptionNode.java | 7 +- .../codeInspection/ui/QuickFixToolbar.java | 94 ++++++----- .../GoToSubsequentOccurrenceAction.java | 26 ++-- 9 files changed, 111 insertions(+), 261 deletions(-) delete mode 100644 platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java index 2fb8e2290147..00a29f113db4 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInspection.CommonProblemDescriptor; import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.QuickFix; import com.intellij.codeInspection.reference.RefElement; import com.intellij.codeInspection.reference.RefEntity; import com.intellij.codeInspection.reference.RefManagerImpl; diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java deleted file mode 100644 index 5114807f04c1..000000000000 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/BatchProblemDescriptor.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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. - */ -package com.intellij.codeInspection.ui; - -import com.intellij.codeInspection.CommonProblemDescriptor; -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemDescriptorBase; -import com.intellij.codeInspection.QuickFix; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.MultiMap; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -/** - * @author Dmitry Batkovich - */ -public class BatchProblemDescriptor { - private final static Logger LOG = Logger.getInstance(BatchProblemDescriptor.class); - - private MultiMap myMap = null; - private final LinkedHashSet myDescriptors = new LinkedHashSet<>(); - private final boolean myOnlyCount; - - public BatchProblemDescriptor(boolean count) { - myOnlyCount = count; - } - - public void addProblem(@Nullable CommonProblemDescriptor descriptor) { - myDescriptors.add(descriptor); - if (myOnlyCount) { - return; - } - if (isIntersectionTrivial()) { - return; - } - final boolean exist; - if (myMap == null) { - myMap = new MultiMap<>(); - exist = false; - } - else { - exist = true; - } - if (descriptor == null) { - myMap.clear(); - return; - } - final QuickFix[] fixes = descriptor.getFixes(); - if (fixes != null) { - MultiMap mapToUse = exist ? new MultiMap<>() : myMap; - for (QuickFix fix : fixes) { - mapToUse.putValue(fix.getName(), descriptor); - } - if (exist) { - for (String name : new ArrayList<>(myMap.keySet())) { - if (mapToUse.containsKey(name)) { - myMap.put(name, mapToUse.get(name)); - } - else { - myMap.remove(name); - } - } - } - } - } - - public static BatchProblemDescriptor single(@Nullable CommonProblemDescriptor descriptor) { - final BatchProblemDescriptor intersector = new BatchProblemDescriptor(false); - intersector.addProblem(descriptor); - return intersector; - } - - public PsiElement getProblemElementIfOnlyOne() { - if (myDescriptors.size() != 1) { - return null; - } - CommonProblemDescriptor descriptor = myDescriptors.iterator().next(); - if (descriptor instanceof ProblemDescriptorBase) { - return ((ProblemDescriptorBase)descriptor).getPsiElement(); - } - return null; - } - - public int getProblemCount() { - return myDescriptors.size(); - } - - @Nullable - public PsiElement getFirstProblemElement() { - for (CommonProblemDescriptor descriptor : myDescriptors) { - if (descriptor == null) continue; - final PsiElement element = ((ProblemDescriptorBase)descriptor).getPsiElement(); - if (element != null) { - return element; - } - } - return null; - } - - @NotNull - public List getQuickFixRepresentatives() { - LOG.assertTrue(!myOnlyCount); - List result = new ArrayList<>(myMap.size()); - for (Map.Entry> e : myMap.entrySet()) { - final String fixName = e.getKey(); - final Collection descriptors = e.getValue(); - final CommonProblemDescriptor representative = ContainerUtil.getFirstItem(descriptors); - LOG.assertTrue(representative != null); - QuickFix[] fixes = representative.getFixes(); - LOG.assertTrue(fixes != null); - for (QuickFix fix : fixes) { - if (fix.getName().equals(fixName)) { - result.add(fix); - break; - } - } - } - return result; - } - - public boolean isIntersectionTrivial() { - LOG.assertTrue(!myOnlyCount); - return myMap != null && myMap.isEmpty(); - } - - public List getDescriptors() { - return new ArrayList<>(myDescriptors); - } -} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNode.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNode.java index b923325f3aab..bde4f550e5aa 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNode.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNode.java @@ -51,7 +51,7 @@ public class InspectionNode extends InspectionTreeNode { public boolean isTooBigForOnlineRefresh() { if (!myTooBigForOnlineRefresh) { - myTooBigForOnlineRefresh = accumulateProblemInfo(new BatchProblemDescriptor(true)).getProblemCount() > 1000; + myTooBigForOnlineRefresh = getProblemCount() > 1000; } return myTooBigForOnlineRefresh; } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index a2efd9c01ab5..08c22d12a791 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -81,7 +81,6 @@ import java.util.*; import java.util.HashSet; import java.util.List; import java.util.concurrent.ConcurrentMap; -import java.util.stream.Collectors; /** * @author max @@ -399,18 +398,18 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren final RefEntity refSelected = refElementNode.getElement(); if (node.isLeaf()) { LOG.assertTrue(problem != null); - showInRightPanel(refSelected, BatchProblemDescriptor.single(problem), node.isValid()); + showInRightPanel(refSelected); } else { - showInRightPanel(refSelected, node.accumulateProblemInfo(new BatchProblemDescriptor(false)), node.isValid()); + showInRightPanel(refSelected); } } else if (node instanceof ProblemDescriptionNode) { final ProblemDescriptionNode problemNode = (ProblemDescriptionNode)node; - showInRightPanel(problemNode.getElement(), BatchProblemDescriptor.single(problemNode.getDescriptor()), node.isValid()); + showInRightPanel(problemNode.getElement()); } else if (node instanceof InspectionNode) { - showInRightPanel(null, node.accumulateProblemInfo(new BatchProblemDescriptor(false)), node.isValid()); + showInRightPanel(null); } else if (node instanceof InspectionRootNode || node instanceof InspectionGroupNode) { mySplitter.setSecondComponent(new InspectionViewNavigationPanel(node, myTree)); @@ -422,41 +421,35 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } } - private void showInRightPanel(final RefEntity refEntity, BatchProblemDescriptor descriptor, boolean valid) { + private void showInRightPanel(@Nullable final RefEntity refEntity) { Cursor currentCursor = getCursor(); try { setCursor(new Cursor(Cursor.WAIT_CURSOR)); - if (descriptor != null) { - final JPanel editorPanel = new JPanel(); - editorPanel.setLayout(new BorderLayout()); - PsiElement containingElement = descriptor.getProblemElementIfOnlyOne(); - if (containingElement == null && refEntity instanceof RefElement) { - containingElement = ((RefElement)refEntity).getElement(); - } - editorPanel.add(createBaseRightComponentFor(containingElement, descriptor), BorderLayout.CENTER); - if (valid && descriptor.getProblemCount() > 0) { - editorPanel.add(new QuickFixToolbar(descriptor, - myTree.getSelectedToolWrapper(), - myTree.getSelectionPaths()[0], - myProject, - myPreviewEditor, - containingElement), - BorderLayout.NORTH); - } - mySplitter.setSecondComponent(editorPanel); + final JPanel editorPanel = new JPanel(); + editorPanel.setLayout(new BorderLayout()); + CommonProblemDescriptor[] descriptors = myTree.getSelectedDescriptors(); + editorPanel.add(createBaseRightComponentFor(descriptors, refEntity), BorderLayout.CENTER); + if (descriptors.length > 0) { + editorPanel.add(new QuickFixToolbar(myTree, + myProject, + myPreviewEditor, + myProvider.getQuickFixes(myTree.getSelectedToolWrapper(), myTree)), + BorderLayout.NORTH); } + mySplitter.setSecondComponent(editorPanel); } finally { setCursor(currentCursor); } } - private JComponent createBaseRightComponentFor(PsiElement containingElement, BatchProblemDescriptor descriptor) { - final int count = descriptor.getProblemCount(); - if (count == 1 || (containingElement != null && !(containingElement instanceof PsiDirectory))) { - final PsiElement referencedElement = descriptor.getFirstProblemElement(); - final PsiFile file = referencedElement.getContainingFile(); - final Document document = PsiDocumentManager.getInstance(referencedElement.getProject()).getDocument(file); + private JComponent createBaseRightComponentFor(CommonProblemDescriptor[] descriptors, + RefEntity selectedEntity) { + final int count = descriptors.length; + if (selectedEntity instanceof RefElement && !(((RefElement)selectedEntity).getElement() instanceof PsiDirectory)) { + PsiElement selectedElement = ((RefElement)selectedEntity).getElement(); + final PsiFile file = selectedElement.getContainingFile(); + final Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); myPreviewEditor = EditorFactory.getInstance().createEditor(document, myProject, file.getVirtualFile(), true); final EditorSettings settings = myPreviewEditor.getSettings(); settings.setLineNumbersShown(false); @@ -466,21 +459,19 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren settings.setLeadingWhitespaceShown(true); settings.setRightMarginShown(true); settings.setRightMargin(60); + PsiElement toHighlight = selectedElement; if (count != 1) { - myPreviewEditor.getCaretModel().moveToOffset(referencedElement.getTextOffset()); + myPreviewEditor.getCaretModel().moveToOffset(selectedElement.getTextOffset()); myPreviewEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + } else if (descriptors[0] instanceof ProblemDescriptorBase) { + toHighlight = ((ProblemDescriptorBase) descriptors[0]).getPsiElement(); } - UsagePreviewPanel - .highlight(containingElement == null - ? Collections.emptyList() - : getElementToHighlight(containingElement), - myPreviewEditor, myProject); + UsagePreviewPanel.highlight(getElementToHighlight(toHighlight), myPreviewEditor, myProject); return myPreviewEditor.getComponent(); } - else if (count > 1) { + else if (selectedEntity == null) { return new InspectionNodeInfo(myTree.getSelectedToolWrapper(), myProject); } - //TODO must not happen return new JPanel(); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java index ad1e87766b07..266aed45f325 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java @@ -166,12 +166,23 @@ public class InspectionTree extends Tree { public CommonProblemDescriptor[] getSelectedDescriptors() { if (getSelectionCount() == 0) return EMPTY_DESCRIPTORS; final TreePath[] paths = getSelectionPaths(); - if (paths == null) return EMPTY_DESCRIPTORS; - BatchProblemDescriptor accumulator = new BatchProblemDescriptor(true); + final LinkedHashSet descriptors = new LinkedHashSet(); for (TreePath path : paths) { - ((InspectionTreeNode)path.getLastPathComponent()).accumulateProblemInfo(accumulator); + Object node = path.getLastPathComponent(); + traverseDescriptors((InspectionTreeNode)node, descriptors); + } + return descriptors.toArray(new CommonProblemDescriptor[descriptors.size()]); + } + + private static void traverseDescriptors(InspectionTreeNode node, LinkedHashSet descriptors){ + if (node instanceof ProblemDescriptionNode) { + if (node.isValid() && !node.isResolved()) { + descriptors.add(((ProblemDescriptionNode)node).getDescriptor()); + } + } + for(int i = node.getChildCount() - 1; i >= 0; i--){ + traverseDescriptors((InspectionTreeNode)node.getChildAt(i), descriptors); } - return accumulator.getDescriptors().toArray(new CommonProblemDescriptor[accumulator.getProblemCount()]); } private void nodeStructureChanged(InspectionTreeNode node) { @@ -248,7 +259,7 @@ public class InspectionTree extends Tree { append(node.toString(), patchAttr(node, appearsBold(node) ? SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES : getMainForegroundAttributes(node))); - int problemCount = node.accumulateProblemInfo(new BatchProblemDescriptor(true)).getProblemCount(); + int problemCount = node.getProblemCount(); if (!leaf) { append(" " + InspectionsBundle.message("inspection.problem.descriptor.count", problemCount), patchAttr(node, SimpleTextAttributes.GRAYED_ATTRIBUTES)); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeNode.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeNode.java index 0f90b155dff8..11977eb09dca 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeNode.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeNode.java @@ -35,13 +35,14 @@ public abstract class InspectionTreeNode extends DefaultMutableTreeNode { @Nullable public abstract Icon getIcon(boolean expanded); - public BatchProblemDescriptor accumulateProblemInfo(BatchProblemDescriptor accumulator) { + public int getProblemCount() { + int sum = 0; Enumeration enumeration = children(); while (enumeration.hasMoreElements()) { InspectionTreeNode child = (InspectionTreeNode)enumeration.nextElement(); - child.accumulateProblemInfo(accumulator); + sum += child.getProblemCount(); } - return accumulator; + return sum; } public boolean isValid() { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java index 7b4dea8826c5..18e41a82f62c 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java @@ -88,11 +88,8 @@ public class ProblemDescriptionNode extends InspectionTreeNode { } @Override - public BatchProblemDescriptor accumulateProblemInfo(BatchProblemDescriptor accumulator) { - if (isValid()) { - accumulator.addProblem(getDescriptor()); - } - return accumulator; + public int getProblemCount() { + return 1; } @Override diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index ec3a73031c1d..7545435e6422 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -15,11 +15,11 @@ */ package com.intellij.codeInspection.ui; -import com.intellij.codeInsight.intention.HighPriorityAction; -import com.intellij.codeInsight.intention.LowPriorityAction; +import com.intellij.codeInspection.CommonProblemDescriptor; import com.intellij.codeInspection.QuickFix; import com.intellij.codeInspection.ex.InspectionToolWrapper; -import com.intellij.codeInspection.ex.LocalQuickFixWrapper; +import com.intellij.codeInspection.ex.QuickFixAction; +import com.intellij.codeInspection.reference.RefElement; import com.intellij.codeInspection.ui.actions.SuppressActionWrapper; import com.intellij.codeInspection.ui.actions.occurrences.GoToSubsequentOccurrenceAction; import com.intellij.icons.AllIcons; @@ -42,10 +42,8 @@ import javax.swing.*; import javax.swing.tree.TreePath; import java.awt.*; import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.Collection; +import java.util.*; import java.util.List; -import java.util.TreeSet; import java.util.function.Supplier; /** @@ -54,15 +52,14 @@ import java.util.function.Supplier; public class QuickFixToolbar extends JPanel { private static final int MAX_FIX_COUNT = 2; - public QuickFixToolbar(@NotNull BatchProblemDescriptor descriptor, - @NotNull InspectionToolWrapper toolWrapper, - @NotNull TreePath path, + public QuickFixToolbar(@NotNull InspectionTree tree, @NotNull Project project, @Nullable Editor editor, - @Nullable PsiElement containingElement) { - final List fixes = descriptor.getQuickFixRepresentatives(); - final boolean hasFixes = !fixes.isEmpty(); - final boolean multipleDescriptors = descriptor.getProblemCount() > 1; + @Nullable QuickFixAction[] fixes) { + final boolean hasFixes = fixes != null && fixes.length != 0; + CommonProblemDescriptor[] descriptors = tree.getSelectedDescriptors(); + int problemCount = descriptors.length; + final boolean multipleDescriptors = problemCount > 1; setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); List panels = new ArrayList<>(); @@ -77,17 +74,19 @@ public class QuickFixToolbar extends JPanel { fill(getBulbPlacement(hasFixes), QuickFixToolbar::createBulbIcon, panels); fill(getDescriptionLabelPlacement(multipleDescriptors), - () -> getLabel(hasFixes, (PsiNamedElement)containingElement, descriptor.getProblemCount()), panels); - fill(getFixesPlacement(hasFixes, multipleDescriptors), () -> createFixPanel(fixes, toolWrapper), panels); - fill(getSuppressPlacement(multipleDescriptors), () -> createSuppressionCombo(toolWrapper, path, project), panels); + () -> getLabel(hasFixes, (InspectionTreeNode)tree.getSelectionPath().getLastPathComponent(), problemCount), panels); + fill(getFixesPlacement(hasFixes, multipleDescriptors), () -> createFixPanel(fixes), panels); + fill(getSuppressPlacement(multipleDescriptors), () -> createSuppressionCombo(tree.getSelectedToolWrapper() + , tree.getSelectionPath(), project), panels); fill(multipleDescriptors && editor != null ? 1 : -1, () -> ActionManager.getInstance().createActionToolbar("", GoToSubsequentOccurrenceAction.createNextPreviousActions( - editor, descriptor.getDescriptors()), true).getComponent(), panels); + editor, descriptors), true).getComponent(), panels); } @NotNull - private static JLabel getLabel(boolean hasFixes, PsiNamedElement target, int problemsCount) { + private static JLabel getLabel(boolean hasFixes, InspectionTreeNode targetNode, int problemsCount) { + final String targetName = targetNode instanceof RefElementNode ? ((RefElementNode)targetNode).getElement().getName() : null; final JBLabel label = - new JBLabel((hasFixes ? " Fix " : " ") + problemsCount + " warnings " + (target == null ? "" : ("in " + target.getName()))); + new JBLabel((hasFixes ? " Fix " : " ") + problemsCount + " warnings " + (targetName == null ? "" : ("in " + targetName))); Font font = label.getFont(); if (!hasFixes) { label.setBorder(IdeBorderFactory.createEmptyBorder(0, 3, 6, 0)); @@ -122,29 +121,9 @@ public class QuickFixToolbar extends JPanel { } @NotNull - private static JPanel createFixPanel(List fixes, - InspectionToolWrapper toolWrapper) { - final Collection sortedFixes; - if (fixes.size() == 1) { - sortedFixes = fixes; - } - else { - sortedFixes = new TreeSet<>((fix1, fix2) -> { - int rate1 = 0; - if (fix1 instanceof HighPriorityAction) rate1 = -1; - if (fix1 instanceof LowPriorityAction) rate1 = 1; - int rate2 = 0; - if (fix2 instanceof HighPriorityAction) rate2 = -1; - if (fix2 instanceof LowPriorityAction) rate2 = 1; - if (rate1 != rate2) { - return rate1 - rate2; - } - return fix1.getName().compareTo(fix2.getName()); - }); - sortedFixes.addAll(fixes); - } + private static JPanel createFixPanel(QuickFixAction[] fixes) { JPanel fixPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, JBUI.scale(3), JBUI.scale(5))); - if (sortedFixes.size() > MAX_FIX_COUNT) { + if (fixes.length > MAX_FIX_COUNT) { final ComboBoxAction fixComboBox = new ComboBoxAction() { { getTemplatePresentation().setText("Apply quick fixes"); @@ -155,8 +134,8 @@ public class QuickFixToolbar extends JPanel { @Override protected DefaultActionGroup createPopupActionGroup(JComponent button) { final DefaultActionGroup actionGroup = new DefaultActionGroup(); - for (QuickFix fix : sortedFixes) { - actionGroup.add(new LocalQuickFixWrapper(fix, toolWrapper)); + for (QuickFixAction fix : fixes) { + actionGroup.add(fix); } return actionGroup; } @@ -164,8 +143,8 @@ public class QuickFixToolbar extends JPanel { fixPanel.add(fixComboBox.createCustomComponent(fixComboBox.getTemplatePresentation())); } else { - for (QuickFix fix : sortedFixes) { - fixPanel.add(createQuickFixButton(fix, toolWrapper)); + for (QuickFixAction fix : fixes) { + fixPanel.add(createQuickFixButton(fix)); } } return fixPanel; @@ -197,16 +176,20 @@ public class QuickFixToolbar extends JPanel { return hasQuickFixes ? 0 : -1; } - private static JComponent createQuickFixButton(@NotNull QuickFix fix, @NotNull InspectionToolWrapper toolWrapper) { - final MyCustomComponentLocalQuickFixWrapper action = new MyCustomComponentLocalQuickFixWrapper(fix, toolWrapper); + private static JComponent createQuickFixButton(@NotNull QuickFixAction fix) { + final MyCustomComponentLocalQuickFixWrapper action = new MyCustomComponentLocalQuickFixWrapper(fix); return action.createCustomComponent(action.getTemplatePresentation()); } - private static class MyCustomComponentLocalQuickFixWrapper extends LocalQuickFixWrapper implements CustomComponentAction { - public MyCustomComponentLocalQuickFixWrapper(@NotNull QuickFix fix, @NotNull InspectionToolWrapper toolWrapper) { - super(fix, toolWrapper); + private static class MyCustomComponentLocalQuickFixWrapper extends AnAction implements CustomComponentAction { + private QuickFixAction myUnderlying; + + public MyCustomComponentLocalQuickFixWrapper(@NotNull QuickFixAction underlying) { + myUnderlying = underlying; + getTemplatePresentation().setText(underlying.getTemplatePresentation().getText()); } + @Override public JComponent createCustomComponent(Presentation presentation) { final JButton button = new JButton(presentation.getText()); @@ -222,5 +205,16 @@ public class QuickFixToolbar extends JPanel { }.installOn(button); return button; } + + + @Override + public void update(AnActionEvent e) { + myUnderlying.update(e); + } + + @Override + public void actionPerformed(AnActionEvent e) { + myUnderlying.actionPerformed(e); + } } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java index 5e979cc8d6f9..0e132dd62c5b 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java @@ -33,6 +33,7 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -61,20 +62,20 @@ public class GoToSubsequentOccurrenceAction extends AnAction { myManager.selectSubsequent(myNext); } - public static ActionGroup createNextPreviousActions(@NotNull Editor editor, @NotNull List descriptors) { + public static ActionGroup createNextPreviousActions(@NotNull Editor editor, @NotNull CommonProblemDescriptor[] descriptors) { OccurrencesManager manager = new OccurrencesManager(editor, descriptors); return new DefaultActionGroup(new GoToSubsequentOccurrenceAction(false, manager), new GoToSubsequentOccurrenceAction(true, manager)); } private static class OccurrencesManager { private final Editor myEditor; - private final List myChildren; + private final ProblemDescriptorBase[] myChildren; private int mySelected = -1; - private OccurrencesManager(@NotNull Editor editor, @NotNull List descriptors) { + private OccurrencesManager(@NotNull Editor editor, @NotNull CommonProblemDescriptor[] descriptors) { myEditor = editor; - myChildren = descriptors.stream() + myChildren = Arrays.stream(descriptors) .filter(d -> d instanceof ProblemDescriptorBase) .map(d -> (ProblemDescriptorBase) d) .filter(d -> { @@ -82,7 +83,7 @@ public class GoToSubsequentOccurrenceAction extends AnAction { return element != null && element.isValid(); }) .sorted((o1, o2) -> o1.getPsiElement().getTextOffset() - o2.getPsiElement().getTextOffset()) - .collect(Collectors.toList()); + .toArray(ProblemDescriptorBase[]::new); selectSubsequent(true); } @@ -90,12 +91,12 @@ public class GoToSubsequentOccurrenceAction extends AnAction { int subsequentIdz = mySelected; while (true) { subsequentIdz += next ? 1 : -1; - subsequentIdz += myChildren.size(); - subsequentIdz %= myChildren.size(); + subsequentIdz += myChildren.length; + subsequentIdz %= myChildren.length; if (mySelected == subsequentIdz) { throw new IllegalStateException("Selection is unavailable"); } - ProblemDescriptorBase descriptorBase = myChildren.get(subsequentIdz); + ProblemDescriptorBase descriptorBase = myChildren[subsequentIdz]; if (descriptorBase.getPsiElement().isValid()) { mySelected = subsequentIdz; PsiElement toSelect = descriptorBase.getPsiElement(); @@ -110,13 +111,14 @@ public class GoToSubsequentOccurrenceAction extends AnAction { public boolean hasValidSubsequent() { int subsequentIdz = mySelected; while (true) { - subsequentIdz += 1 + myChildren.size(); - subsequentIdz %= myChildren.size(); + subsequentIdz += 1 + myChildren.length; + subsequentIdz %= myChildren.length; if (mySelected == subsequentIdz) { return false; } - ProblemDescriptorBase descriptorBase = myChildren.get(subsequentIdz); - if (descriptorBase.getPsiElement().isValid()) { + ProblemDescriptorBase descriptorBase = myChildren[subsequentIdz]; + PsiElement element = descriptorBase.getPsiElement(); + if (element != null && element.isValid()) { return true; } } From 34a4621fd13e86883936c52adef9d6177be9c3ae Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 15 Feb 2016 12:50:28 +0300 Subject: [PATCH 20/84] inspection tool window: sync right panel --- .../codeInspection/ex/QuickFixAction.java | 16 +++++-------- .../ui/InspectionResultsView.java | 24 +++++++++---------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java index 00a29f113db4..29fe06ddf186 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java @@ -20,7 +20,6 @@ import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInspection.CommonProblemDescriptor; import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.codeInspection.QuickFix; import com.intellij.codeInspection.reference.RefElement; import com.intellij.codeInspection.reference.RefEntity; import com.intellij.codeInspection.reference.RefManagerImpl; @@ -42,7 +41,6 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiUtilCore; -import com.intellij.util.ArrayUtil; import com.intellij.util.SequentialModalProgressTask; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; @@ -111,15 +109,13 @@ public class QuickFixAction extends AnAction { public void actionPerformed(final AnActionEvent e) { final InspectionResultsView view = getInvoker(e); final InspectionTree tree = view.getTree(); - if (isProblemDescriptorsAcceptable()) { - final CommonProblemDescriptor[] descriptors = tree.getSelectedDescriptors(); - if (descriptors.length > 0) { - doApplyFix(view.getProject(), descriptors, tree.getContext()); - return; - } + final CommonProblemDescriptor[] descriptors; + if (isProblemDescriptorsAcceptable() && (descriptors = tree.getSelectedDescriptors()).length > 0) { + doApplyFix(view.getProject(), descriptors, tree.getContext()); + } else { + doApplyFix(getSelectedElements(e), view); } - - doApplyFix(getSelectedElements(e), view); + view.updateRightPanel(); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 08c22d12a791..40ce20a3c1d0 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -134,12 +134,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren mySplitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myTree, SideBorder.LEFT | SideBorder.RIGHT)); - mySplitter.addPropertyChangeListener(new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (Splitter.PROP_PROPORTION.equals(evt.getPropertyName())) { - myGlobalInspectionContext.setSplitterProportion(((Float)evt.getNewValue()).floatValue()); - } + mySplitter.addPropertyChangeListener(evt -> { + if (Splitter.PROP_PROPORTION.equals(evt.getPropertyName())) { + myGlobalInspectionContext.setSplitterProportion(((Float)evt.getNewValue()).floatValue()); } }); add(mySplitter, BorderLayout.CENTER); @@ -149,13 +146,10 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } private void initTreeListeners() { - myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { - @Override - public void valueChanged(TreeSelectionEvent e) { - syncRightPanel(); - if (isAutoScrollMode()) { - OpenSourceUtil.openSourcesFrom(DataManager.getInstance().getDataContext(InspectionResultsView.this), false); - } + myTree.getSelectionModel().addTreeSelectionListener(e -> { + syncRightPanel(); + if (isAutoScrollMode()) { + OpenSourceUtil.openSourcesFrom(DataManager.getInstance().getDataContext(InspectionResultsView.this), false); } }); @@ -848,6 +842,10 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren return myScope; } + public void updateRightPanel() { + syncRightPanel(); + } + private class CloseAction extends AnAction implements DumbAware { private CloseAction() { super(CommonBundle.message("action.close"), null, AllIcons.Actions.Cancel); From 1bcf084e602743cf39f4a4eea0a82cca2c2e36e8 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 15 Feb 2016 19:32:04 +0300 Subject: [PATCH 21/84] inspection tool window: descriptors intersection instead of union --- .../DummyEntryPointsPresentation.java | 3 +- .../UnusedDeclarationPresentation.java | 2 +- .../codeInspection/ex/DescriptorComposer.java | 2 +- .../ex/InspectionRVContentProviderImpl.java | 2 +- .../OfflineInspectionRVContentProvider.java | 22 ++---- .../ui/DefaultInspectionToolPresentation.java | 72 ++++++++++++------- .../ui/InspectionResultsView.java | 6 +- .../ui/InspectionToolPresentation.java | 6 +- 8 files changed, 64 insertions(+), 51 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java index 20465b1fe919..c9be5d934b3d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInspection.deadCode; +import com.intellij.codeInspection.CommonProblemDescriptor; import com.intellij.codeInspection.GlobalJavaInspectionContext; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.ex.*; @@ -39,7 +40,7 @@ public class DummyEntryPointsPresentation extends UnusedDeclarationPresentation } @Override - public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements) { + public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) { if (myQuickFixActions == null) { myQuickFixActions = new QuickFixAction[]{new MoveEntriesToSuspicious(getToolWrapper())}; } diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java index 76602ca1c660..ad13714f3cc7 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java @@ -145,7 +145,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta } @Override - public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements) { + public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) { return myQuickFixActions; } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorComposer.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorComposer.java index 0dbd17105a1b..b9f2be991410 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorComposer.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorComposer.java @@ -75,7 +75,7 @@ public class DescriptorComposer extends HTMLComposerImpl { } public static String[] quickFixTexts(RefEntity where, @NotNull InspectionToolPresentation toolPresentation){ - QuickFixAction[] quickFixes = toolPresentation.getQuickFixes(new RefEntity[] {where}); + QuickFixAction[] quickFixes = toolPresentation.getQuickFixes(new RefEntity[] {where}, null); if (quickFixes == null) { return null; } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProviderImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProviderImpl.java index 1cf2714e7840..5db74ec6f5c6 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProviderImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProviderImpl.java @@ -83,7 +83,7 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider public QuickFixAction[] getQuickFixes(@NotNull final InspectionToolWrapper toolWrapper, @NotNull final InspectionTree tree) { final RefEntity[] refEntities = tree.getSelectedElements(); InspectionToolPresentation presentation = tree.getContext().getPresentation(toolWrapper); - return refEntities.length == 0 ? null : presentation.getQuickFixes(refEntities); + return refEntities.length == 0 ? null : presentation.getQuickFixes(refEntities, tree.getSelectedDescriptors()); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/offlineViewer/OfflineInspectionRVContentProvider.java b/platform/lang-impl/src/com/intellij/codeInspection/offlineViewer/OfflineInspectionRVContentProvider.java index db99eb2ff6ca..7db298c8ddff 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/offlineViewer/OfflineInspectionRVContentProvider.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/offlineViewer/OfflineInspectionRVContentProvider.java @@ -21,7 +21,6 @@ package com.intellij.codeInspection.offlineViewer; import com.intellij.codeInspection.CommonProblemDescriptor; -import com.intellij.codeInspection.QuickFix; import com.intellij.codeInspection.ex.*; import com.intellij.codeInspection.offline.OfflineProblemDescriptor; import com.intellij.codeInspection.reference.RefElement; @@ -31,7 +30,6 @@ import com.intellij.codeInspection.ui.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; @@ -69,7 +67,7 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi final TreePath[] treePaths = tree.getSelectionPaths(); if (treePaths == null) return QuickFixAction.EMPTY; final List selectedElements = new ArrayList(); - final Map> actions = new HashMap>(); + final Map actions = new HashMap<>(); for (TreePath selectionPath : treePaths) { TreeUtil.traverseDepth((TreeNode)selectionPath.getLastPathComponent(), new TreeUtil.Traverse() { @Override @@ -79,18 +77,10 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi final OfflineProblemDescriptorNode descriptorNode = (OfflineProblemDescriptorNode)node; final RefEntity element = descriptorNode.getElement(); selectedElements.add(element); - Set quickFixes = actions.get(element); - if (quickFixes == null) { - quickFixes = new HashSet(); - actions.put(element, quickFixes); - } - final CommonProblemDescriptor descriptor = descriptorNode.getDescriptor(); - if (descriptor != null) { - final QuickFix[] fixes = descriptor.getFixes(); - if (fixes != null) { - ContainerUtil.addAll(quickFixes, fixes); - } - } + CommonProblemDescriptor[] quickFixes = actions.get(element); + actions.put(element, quickFixes == null ? + new CommonProblemDescriptor[]{descriptorNode.getDescriptor()} : + DefaultInspectionToolPresentation.mergeDescriptors(quickFixes, new CommonProblemDescriptor[]{descriptorNode.getDescriptor()})); } else if (node instanceof RefElementNode) { selectedElements.add(((RefElementNode)node).getElement()); @@ -106,7 +96,7 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi GlobalInspectionContextImpl context = tree.getContext(); InspectionToolPresentation presentation = context.getPresentation(toolWrapper); - return presentation.extractActiveFixes(selectedRefElements, actions); + return presentation.extractActiveFixes(selectedRefElements, actions, tree.getSelectedDescriptors()); } @Override diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java index e0dea90be811..d88e267fcaf8 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java @@ -267,7 +267,7 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro } @NotNull - private static CommonProblemDescriptor[] mergeDescriptors(@NotNull CommonProblemDescriptor[] problems1, + public static CommonProblemDescriptor[] mergeDescriptors(@NotNull CommonProblemDescriptor[] problems1, @NotNull CommonProblemDescriptor[] problems2) { CommonProblemDescriptor[] out = new CommonProblemDescriptor[problems1.length + problems2.length]; int o = problems1.length; @@ -641,41 +641,65 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro @Override @Nullable - public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements) { - return extractActiveFixes(refElements, getQuickFixActions()); + public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) { + return extractActiveFixes(refElements, getProblemElements(), allowedDescriptors); } @Override @Nullable - public QuickFixAction[] extractActiveFixes(@NotNull RefEntity[] refElements, @NotNull Map> actions) { - Map result = new com.intellij.util.containers.HashMap(); + public QuickFixAction[] extractActiveFixes(@NotNull RefEntity[] refElements, + @NotNull Map descriptorMap, + @Nullable CommonProblemDescriptor[] allowedDescriptors) { + final Set allowedDescriptorSet = allowedDescriptors == null ? null : ContainerUtil.newHashSet(allowedDescriptors); + Map result = new com.intellij.util.containers.HashMap<>(); for (RefEntity refElement : refElements) { - final Set localQuickFixes = actions.get(refElement); - if (localQuickFixes == null) continue; - for (QuickFix fix : localQuickFixes) { - if (fix == null) continue; - final Class klass = fix instanceof ActionClassHolder ? ((ActionClassHolder ) fix).getActionClass() : fix.getClass(); - final QuickFixAction quickFixAction = result.get(klass); - if (quickFixAction != null) { - try { - String familyName = fix.getFamilyName(); - familyName = !familyName.isEmpty() ? "\'" + familyName + "\'" : familyName; - ((LocalQuickFixWrapper)quickFixAction).setText(InspectionsBundle.message("inspection.descriptor.provider.apply.fix", familyName)); - } - catch (AbstractMethodError e) { - //for plugin compatibility - ((LocalQuickFixWrapper)quickFixAction).setText(InspectionsBundle.message("inspection.descriptor.provider.apply.fix", "")); - } + final CommonProblemDescriptor[] descriptors = descriptorMap.get(refElement); + if (descriptors == null) continue; + boolean isFirst = true; + for (CommonProblemDescriptor d : descriptors) { + if (allowedDescriptorSet != null && !allowedDescriptorSet.contains(d)) { + continue; } - else { - LocalQuickFixWrapper quickFixWrapper = new LocalQuickFixWrapper(fix, myToolWrapper); - result.put(klass, quickFixWrapper); + QuickFix[] fixes = d.getFixes(); + if (fixes != null) { + if (isFirst) { + for (QuickFix fix : fixes) { + if (fix == null) continue; + final Class klass = getFixClass(fix); + LocalQuickFixWrapper quickFixWrapper = new LocalQuickFixWrapper(fix, myToolWrapper); + result.put(klass, quickFixWrapper); + } + isFirst = false; + } + else { + for (Class clazz : new ArrayList<>(result.keySet())) { + boolean isFound = false; + for (QuickFix fix : fixes) { + if (fix == null) continue; + final Class klass = getFixClass(fix); + if (clazz.equals(klass)) { + isFound = true; + break; + } + } + if (!isFound) { + result.remove(clazz); + if (result.isEmpty()) { + return null; + } + } + } + } } } } return result.values().isEmpty() ? null : result.values().toArray(new QuickFixAction[result.size()]); } + private static Class getFixClass(QuickFix fix) { + return fix instanceof ActionClassHolder ? ((ActionClassHolder)fix).getActionClass() : fix.getClass(); + } + @Override public RefEntity getElement(@NotNull CommonProblemDescriptor descriptor) { return getProblemToElements().get(descriptor); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 40ce20a3c1d0..9b294a795b30 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -65,8 +65,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreePath; @@ -75,8 +73,6 @@ import java.awt.event.InputEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import java.util.*; import java.util.HashSet; import java.util.List; @@ -486,7 +482,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } private void registerActionShortcuts(@NotNull InspectionToolPresentation presentation) { - final QuickFixAction[] fixes = presentation.getQuickFixes(RefEntity.EMPTY_ELEMENTS_ARRAY); + final QuickFixAction[] fixes = presentation.getQuickFixes(RefEntity.EMPTY_ELEMENTS_ARRAY, null); if (fixes != null) { for (QuickFixAction fix : fixes) { fix.registerCustomShortcutSet(fix.getShortcutSet(), this); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionToolPresentation.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionToolPresentation.java index c7f632575815..fda43559a918 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionToolPresentation.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionToolPresentation.java @@ -67,7 +67,7 @@ public interface InspectionToolPresentation extends ProblemDescriptionsProcessor @NotNull Set getModuleProblems(); @Nullable - QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements); + QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, @Nullable CommonProblemDescriptor[] descriptors); @NotNull Map getProblemElements(); @NotNull @@ -86,6 +86,8 @@ public interface InspectionToolPresentation extends ProblemDescriptionsProcessor GlobalInspectionContextImpl getContext(); void ignoreProblem(RefEntity refEntity, CommonProblemDescriptor problem, int idx); @Nullable - QuickFixAction[] extractActiveFixes(@NotNull RefEntity[] refElements, @NotNull Map> actions); + QuickFixAction[] extractActiveFixes(@NotNull RefEntity[] refElements, + @NotNull Map descriptorMap, + @Nullable CommonProblemDescriptor[] allowedDescriptors); void exportResults(@NotNull final Element parentNode); } From 2c4b86c31d312af4c627832a69ad61d0de9e1ba4 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 15 Feb 2016 20:36:27 +0300 Subject: [PATCH 22/84] inspection tool window: use JEditorPane to show description --- .../config/IntentionDescriptionPanel.java | 2 +- .../codeInspection/ui/InspectionNodeInfo.java | 21 ++++++++++------ .../ui/SingleInspectionProfilePanel.java | 24 +++++++++---------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/IntentionDescriptionPanel.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/IntentionDescriptionPanel.java index a1b596c3bbab..5c6c77fbf1d0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/IntentionDescriptionPanel.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/IntentionDescriptionPanel.java @@ -80,7 +80,7 @@ public class IntentionDescriptionPanel { } } - // TODO 134099: see SingleInspectionProfilePanel#toHTML + // TODO 134099: see SingleInspectionProfilePanel#setHTML private String toHTML(String text) { final HintHint hintHint = new HintHint(myDescriptionBrowser, new Point(0, 0)); hintHint.setFont(UIUtil.getLabelFont()); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java index e933be246ff5..b38828a04261 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java @@ -16,19 +16,15 @@ package com.intellij.codeInspection.ui; import com.intellij.codeInsight.daemon.HighlightDisplayKey; -import com.intellij.codeInspection.ModifiableModel; import com.intellij.codeInspection.ex.DisableInspectionToolAction; import com.intellij.codeInspection.ex.InspectionProfileImpl; import com.intellij.codeInspection.ex.InspectionToolWrapper; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; -import com.intellij.psi.PsiElement; +import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel; import com.intellij.ui.*; -import com.intellij.ui.components.JBLabel; -import com.intellij.ui.components.JBScrollPane; -import com.intellij.util.Consumer; import com.intellij.util.ui.JBInsets; -import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -40,6 +36,8 @@ import java.awt.event.MouseEvent; * @author Dmitry Batkovich */ public class InspectionNodeInfo extends JPanel { + private final static Logger LOG = Logger.getInstance(InspectionNodeInfo.class); + private final JButton myButton; private final SimpleColoredComponent myTitle; private final HighlightDisplayKey myKey; @@ -60,7 +58,16 @@ public class InspectionNodeInfo extends JPanel { add(myTitle, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new JBInsets(0, 2, 0, 0), 0, 0)); - add(new JBLabel(String.valueOf(toolWrapper.loadDescription()), UIUtil.ComponentStyle.SMALL), + + JEditorPane description = new JEditorPane(); + description.setContentType(UIUtil.HTML_MIME); + description.setEditable(false); + description.setOpaque(false); + description.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE); + SingleInspectionProfilePanel.readHTML(description, SingleInspectionProfilePanel.toHTML(description, toolWrapper.loadDescription(), + true)); + + add(description, new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new JBInsets(5, 5, 0, 0), 0, 0)); add(myButton, diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java index e7eaa673acd0..01ab1f67dace 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java @@ -92,8 +92,6 @@ import java.io.StringReader; import java.util.*; import java.util.List; -import com.intellij.util.containers.Queue; - /** * User: anna * Date: 31-May-2006 @@ -773,9 +771,9 @@ public class SingleInspectionProfilePanel extends JPanel { } // TODO 134099: see IntentionDescriptionPanel#readHTML - private boolean readHTML(String text) { + public static boolean readHTML(JEditorPane browser, String text) { try { - myBrowser.read(new StringReader(text), null); + browser.read(new StringReader(text), null); return true; } catch (IOException ignored) { @@ -783,10 +781,10 @@ public class SingleInspectionProfilePanel extends JPanel { } } - // TODO 134099: see IntentionDescriptionPanel#toHTML - private String toHTML(String text) { - final HintHint hintHint = new HintHint(myBrowser, new Point(0, 0)); - hintHint.setFont(UIUtil.getLabelFont()); + // TODO 134099: see IntentionDescriptionPanel#setHTML + public static String toHTML(JEditorPane browser, String text, boolean miniFontSize) { + final HintHint hintHint = new HintHint(browser, new Point(0, 0)); + hintHint.setFont(miniFontSize ? UIUtil.getLabelFont(UIUtil.FontSize.SMALL) : UIUtil.getLabelFont()); return HintUtil.prepareHintText(text, hintHint); } @@ -806,8 +804,8 @@ public class SingleInspectionProfilePanel extends JPanel { final Descriptor defaultDescriptor = singleNode.getDefaultDescriptor(); final String description = defaultDescriptor.loadDescription(); try { - if (!readHTML(SearchUtil.markup(toHTML(description), myProfileFilter.getFilter()))) { - readHTML(toHTML("" + UNDER_CONSTRUCTION + "")); + if (!readHTML(myBrowser, SearchUtil.markup(toHTML(myBrowser, description, false), myProfileFilter.getFilter()))) { + readHTML(myBrowser, toHTML(myBrowser, "" + UNDER_CONSTRUCTION + "", false)); } } catch (Throwable t) { @@ -819,11 +817,11 @@ public class SingleInspectionProfilePanel extends JPanel { } else { - readHTML(toHTML("Can't find inspection description.")); + readHTML(myBrowser, toHTML(myBrowser, "Can't find inspection description.", false)); } } else { - readHTML(toHTML("Multiple inspections are selected. You can edit them as a single inspection.")); + readHTML(myBrowser, toHTML(myBrowser, "Multiple inspections are selected. You can edit them as a single inspection.", false)); } myOptionsPanel.removeAll(); @@ -1021,7 +1019,7 @@ public class SingleInspectionProfilePanel extends JPanel { private void initOptionsAndDescriptionPanel() { myOptionsPanel.removeAll(); - readHTML(EMPTY_HTML); + readHTML(myBrowser, EMPTY_HTML); myOptionsPanel.validate(); myOptionsPanel.repaint(); } From 68b63f2cc8c3613f94c4ac3b537bf0b1ef3e98bc Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 15 Feb 2016 20:47:57 +0300 Subject: [PATCH 23/84] inspection tool window: wrap secription with scroll pane --- .../com/intellij/codeInspection/ui/InspectionNodeInfo.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java index b38828a04261..c6127c741115 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java @@ -24,6 +24,7 @@ import com.intellij.openapi.project.Project; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel; import com.intellij.ui.*; +import com.intellij.ui.components.JBScrollPane; import com.intellij.util.ui.JBInsets; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -67,11 +68,11 @@ public class InspectionNodeInfo extends JPanel { SingleInspectionProfilePanel.readHTML(description, SingleInspectionProfilePanel.toHTML(description, toolWrapper.loadDescription(), true)); - add(description, - new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, + add(ScrollPaneFactory.createScrollPane(description, true), + new GridBagConstraints(0, 1, 1, 1, 0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new JBInsets(5, 5, 0, 0), 0, 0)); add(myButton, - new GridBagConstraints(0, 2, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, + new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new JBInsets(15, 0, 0, 0), 0, 0)); updateEnableButtonText(false); From 50e400050faf0e6e056ec684513ed27a862151bc Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 15 Feb 2016 21:41:41 +0300 Subject: [PATCH 24/84] inspection tool window: move bulb --- .../src/com/intellij/codeInspection/ui/QuickFixToolbar.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index 7545435e6422..721f2e9f3ba3 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -72,7 +72,7 @@ public class QuickFixToolbar extends JPanel { panels.get(0).setBorder(IdeBorderFactory.createEmptyBorder(5, 0, 0, 0)); } - fill(getBulbPlacement(hasFixes), QuickFixToolbar::createBulbIcon, panels); + //fill(getBulbPlacement(hasFixes), QuickFixToolbar::createBulbIcon, panels); fill(getDescriptionLabelPlacement(multipleDescriptors), () -> getLabel(hasFixes, (InspectionTreeNode)tree.getSelectionPath().getLastPathComponent(), problemCount), panels); fill(getFixesPlacement(hasFixes, multipleDescriptors), () -> createFixPanel(fixes), panels); @@ -127,6 +127,7 @@ public class QuickFixToolbar extends JPanel { final ComboBoxAction fixComboBox = new ComboBoxAction() { { getTemplatePresentation().setText("Apply quick fixes"); + getTemplatePresentation().setIcon(AllIcons.Actions.CreateFromUsage); setSmallVariant(false); } @@ -186,13 +187,14 @@ public class QuickFixToolbar extends JPanel { public MyCustomComponentLocalQuickFixWrapper(@NotNull QuickFixAction underlying) { myUnderlying = underlying; - getTemplatePresentation().setText(underlying.getTemplatePresentation().getText()); + copyFrom(underlying); } @Override public JComponent createCustomComponent(Presentation presentation) { final JButton button = new JButton(presentation.getText()); + button.setIcon(presentation.getIcon()); new ClickListener() { @Override public boolean onClick(@NotNull MouseEvent event, int clickCount) { From 604b54ba22d0fc9d56031e3226f80c55d0829cf5 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 15 Feb 2016 22:24:32 +0300 Subject: [PATCH 25/84] inspection tool window: make presentation more beaty --- .../ui/DefaultInspectionToolPresentation.java | 2 +- .../codeInspection/ui/QuickFixToolbar.java | 20 +++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java index d88e267fcaf8..75386d442fbe 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java @@ -685,7 +685,7 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro if (!isFound) { result.remove(clazz); if (result.isEmpty()) { - return null; + return QuickFixAction.EMPTY; } } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index 721f2e9f3ba3..2687490ab297 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -33,6 +33,8 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNamedElement; import com.intellij.ui.ClickListener; import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.SimpleColoredComponent; +import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.components.JBLabel; import com.intellij.util.ui.JBUI; import org.jetbrains.annotations.NotNull; @@ -74,7 +76,7 @@ public class QuickFixToolbar extends JPanel { //fill(getBulbPlacement(hasFixes), QuickFixToolbar::createBulbIcon, panels); fill(getDescriptionLabelPlacement(multipleDescriptors), - () -> getLabel(hasFixes, (InspectionTreeNode)tree.getSelectionPath().getLastPathComponent(), problemCount), panels); + () -> getLabel(fixes, (InspectionTreeNode)tree.getSelectionPath().getLastPathComponent(), problemCount), panels); fill(getFixesPlacement(hasFixes, multipleDescriptors), () -> createFixPanel(fixes), panels); fill(getSuppressPlacement(multipleDescriptors), () -> createSuppressionCombo(tree.getSelectedToolWrapper() , tree.getSelectionPath(), project), panels); @@ -83,15 +85,21 @@ public class QuickFixToolbar extends JPanel { } @NotNull - private static JLabel getLabel(boolean hasFixes, InspectionTreeNode targetNode, int problemsCount) { + private static JComponent getLabel(QuickFixAction[] fixes, InspectionTreeNode targetNode, int problemsCount) { final String targetName = targetNode instanceof RefElementNode ? ((RefElementNode)targetNode).getElement().getName() : null; - final JBLabel label = - new JBLabel((hasFixes ? " Fix " : " ") + problemsCount + " warnings " + (targetName == null ? "" : ("in " + targetName))); - Font font = label.getFont(); + SimpleColoredComponent label = new SimpleColoredComponent(); + boolean hasFixesNonIntersectedFixes = fixes != null && fixes.length == 0; + boolean hasFixes = fixes != null && fixes.length != 0; + label.append((hasFixes ? " Fix " : " ") + problemsCount + " warnings " + (targetName == null ? "" : ("in " + targetName)) + ( + hasFixesNonIntersectedFixes + ? ":" : ""), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); + if (hasFixesNonIntersectedFixes) { + label.append(" select a problem to see its quick fixes"); + } + if (!hasFixes) { label.setBorder(IdeBorderFactory.createEmptyBorder(0, 3, 6, 0)); } - label.setFont(new Font(font.getFontName(), Font.BOLD, font.getSize())); return label; } From 6da072f32d3539ba8a2778202aa4ec7c7b65d559 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 15 Feb 2016 23:13:54 +0300 Subject: [PATCH 26/84] inspection tool window: text fixed --- .../src/com/intellij/codeInspection/ui/QuickFixToolbar.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index 2687490ab297..0aa4ec86788a 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -90,11 +90,11 @@ public class QuickFixToolbar extends JPanel { SimpleColoredComponent label = new SimpleColoredComponent(); boolean hasFixesNonIntersectedFixes = fixes != null && fixes.length == 0; boolean hasFixes = fixes != null && fixes.length != 0; - label.append((hasFixes ? " Fix " : " ") + problemsCount + " warnings " + (targetName == null ? "" : ("in " + targetName)) + ( + label.append((hasFixes ? " Fix " : " ") + problemsCount + " problems" + (targetName == null ? "" : (" in " + targetName)) + ( hasFixesNonIntersectedFixes ? ":" : ""), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); if (hasFixesNonIntersectedFixes) { - label.append(" select a problem to see its quick fixes"); + label.append(" select a single problem to see its quick fixes"); } if (!hasFixes) { From 4066caebca2a393cc3e68afb5b0943f93f01ed6c Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 15 Feb 2016 23:15:59 +0300 Subject: [PATCH 27/84] inspection tool window: fixed alignment --- .../src/com/intellij/codeInspection/ui/QuickFixToolbar.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index 0aa4ec86788a..6aa54f6b0800 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -70,7 +70,7 @@ public class QuickFixToolbar extends JPanel { line.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); panels.add((JPanel)add(line)); } - if (multipleDescriptors) { + if (multipleDescriptors || !hasFixes) { panels.get(0).setBorder(IdeBorderFactory.createEmptyBorder(5, 0, 0, 0)); } From b6db50be6943b7e80fe862f4e275e6bc5bfbfd54 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 15 Feb 2016 23:23:02 +0300 Subject: [PATCH 28/84] inspection tool window: assertion for various grouping is fixed --- .../com/intellij/codeInspection/ui/InspectionResultsView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 9b294a795b30..a49be381f339 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -398,10 +398,10 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren final ProblemDescriptionNode problemNode = (ProblemDescriptionNode)node; showInRightPanel(problemNode.getElement()); } - else if (node instanceof InspectionNode) { + else if (node instanceof InspectionNode || node instanceof InspectionPackageNode || node instanceof InspectionModuleNode) { showInRightPanel(null); } - else if (node instanceof InspectionRootNode || node instanceof InspectionGroupNode) { + else if (node instanceof InspectionRootNode || node instanceof InspectionGroupNode || node instanceof InspectionSeverityGroupNode) { mySplitter.setSecondComponent(new InspectionViewNavigationPanel(node, myTree)); } else { From 64287d1ff575402fe108c09cd399d33be7b40b8a Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 15 Feb 2016 23:36:23 +0300 Subject: [PATCH 29/84] inspection tool window: basic multiselection --- .../codeInspection/ui/InspectionResultsView.java | 14 +++++++++----- .../intellij/codeInspection/ui/InspectionTree.java | 3 +++ .../codeInspection/ui/QuickFixToolbar.java | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index a49be381f339..590b14511e4f 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -371,17 +371,21 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } private void syncRightPanel() { + releaseEditor(); if (myTree.getSelectionModel().getSelectionCount() != 1) { - final JLabel multipleSelectionLabel = new JBLabel(InspectionViewNavigationPanel.getTitleText(false, false)); - multipleSelectionLabel.setVerticalAlignment(SwingConstants.TOP); - multipleSelectionLabel.setBorder(IdeBorderFactory.createEmptyBorder(5, 7, 0, 0)); - mySplitter.setSecondComponent(multipleSelectionLabel); + if (myTree.getSelectedToolWrapper() == null) { + final JLabel multipleSelectionLabel = new JBLabel(InspectionViewNavigationPanel.getTitleText(false, false)); + multipleSelectionLabel.setVerticalAlignment(SwingConstants.TOP); + multipleSelectionLabel.setBorder(IdeBorderFactory.createEmptyBorder(5, 7, 0, 0)); + mySplitter.setSecondComponent(multipleSelectionLabel); + } else { + showInRightPanel(null); + } } else { TreePath pathSelected = myTree.getSelectionModel().getLeadSelectionPath(); if (pathSelected != null) { final InspectionTreeNode node = (InspectionTreeNode)pathSelected.getLastPathComponent(); - releaseEditor(); if (node instanceof RefElementNode) { final RefElementNode refElementNode = (RefElementNode)node; final CommonProblemDescriptor problem = refElementNode.getProblem(); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java index 266aed45f325..f3f53e2a9ef8 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java @@ -109,6 +109,9 @@ public class InspectionTree extends Tree { Object[] nodes = path.getPath(); for (int j = nodes.length - 1; j >= 0; j--) { Object node = nodes[j]; + if (node instanceof InspectionGroupNode) { + return null; + } if (node instanceof InspectionNode) { InspectionToolWrapper wrapper = ((InspectionNode)node).getToolWrapper(); if (toolWrapper == null) { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index 6aa54f6b0800..dcc5f4aa49ce 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -76,7 +76,7 @@ public class QuickFixToolbar extends JPanel { //fill(getBulbPlacement(hasFixes), QuickFixToolbar::createBulbIcon, panels); fill(getDescriptionLabelPlacement(multipleDescriptors), - () -> getLabel(fixes, (InspectionTreeNode)tree.getSelectionPath().getLastPathComponent(), problemCount), panels); + () -> getLabel(fixes, tree.getSelectionCount() == 1 ? (InspectionTreeNode)tree.getSelectionPath().getLastPathComponent() : null, problemCount), panels); fill(getFixesPlacement(hasFixes, multipleDescriptors), () -> createFixPanel(fixes), panels); fill(getSuppressPlacement(multipleDescriptors), () -> createSuppressionCombo(tree.getSelectedToolWrapper() , tree.getSelectionPath(), project), panels); From 19eca6f4dc33f5f01dd74d08fac35f2216ef97c5 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 16 Feb 2016 10:59:22 +0300 Subject: [PATCH 30/84] inspections: problem naviagtion fixed --- .../ui/InspectionResultsView.java | 27 ++++++++++++++----- .../GoToSubsequentOccurrenceAction.java | 13 ++++++--- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 590b14511e4f..2cf5f57bfde2 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -35,6 +35,7 @@ import com.intellij.injected.editor.VirtualFileWindow; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; import com.intellij.openapi.fileEditor.OpenFileDescriptor; @@ -442,6 +443,15 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren final int count = descriptors.length; if (selectedEntity instanceof RefElement && !(((RefElement)selectedEntity).getElement() instanceof PsiDirectory)) { PsiElement selectedElement = ((RefElement)selectedEntity).getElement(); + if (count == 1) { + final CommonProblemDescriptor descriptor = descriptors[0]; + if (descriptor instanceof ProblemDescriptorBase) { + final PsiElement element = ((ProblemDescriptorBase)descriptor).getPsiElement(); + if (element != null) { + selectedElement = element; + } + } + } final PsiFile file = selectedElement.getContainingFile(); final Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); myPreviewEditor = EditorFactory.getInstance().createEditor(document, myProject, file.getVirtualFile(), true); @@ -453,14 +463,17 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren settings.setLeadingWhitespaceShown(true); settings.setRightMarginShown(true); settings.setRightMargin(60); - PsiElement toHighlight = selectedElement; - if (count != 1) { - myPreviewEditor.getCaretModel().moveToOffset(selectedElement.getTextOffset()); - myPreviewEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); - } else if (descriptors[0] instanceof ProblemDescriptorBase) { - toHighlight = ((ProblemDescriptorBase) descriptors[0]).getPsiElement(); + UsagePreviewPanel.highlight(Collections.emptyList(), myPreviewEditor, myProject); + if (count == 1) { + final PsiElement finalSelectedElement = selectedElement; + ApplicationManager.getApplication().invokeLater(() -> { + if (myPreviewEditor != null && !myPreviewEditor.isDisposed()) { + PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + myPreviewEditor.getCaretModel().moveToOffset(finalSelectedElement.getTextOffset()); + myPreviewEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + } + }, ModalityState.NON_MODAL); } - UsagePreviewPanel.highlight(getElementToHighlight(toHighlight), myPreviewEditor, myProject); return myPreviewEditor.getComponent(); } else if (selectedEntity == null) { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java index 0e132dd62c5b..eca22402d973 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java @@ -29,6 +29,7 @@ import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; +import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; @@ -99,10 +100,14 @@ public class GoToSubsequentOccurrenceAction extends AnAction { ProblemDescriptorBase descriptorBase = myChildren[subsequentIdz]; if (descriptorBase.getPsiElement().isValid()) { mySelected = subsequentIdz; - PsiElement toSelect = descriptorBase.getPsiElement(); - myEditor.getCaretModel().moveToOffset(toSelect.getTextOffset()); - myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); - myEditor.getSelectionModel().setSelection(toSelect.getTextRange().getStartOffset(), toSelect.getTextRange().getEndOffset()); + ApplicationManager.getApplication().invokeLater(() -> { + if (myEditor == null || myEditor.isDisposed()) return; + PsiElement toSelect = descriptorBase.getPsiElement(); + PsiDocumentManager.getInstance(myEditor.getProject()).commitAllDocuments(); + myEditor.getCaretModel().moveToOffset(toSelect.getTextOffset()); + myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + myEditor.getSelectionModel().setSelection(toSelect.getTextRange().getStartOffset(), toSelect.getTextRange().getEndOffset()); + }, ModalityState.NON_MODAL); return; } } From 2299628fcb2cf341d5c07d72b5984b187f3842ec Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 16 Feb 2016 12:05:46 +0300 Subject: [PATCH 31/84] inspections: multiple selection for common RefElementNode --- .../ui/InspectionResultsView.java | 5 ++-- .../codeInspection/ui/InspectionTree.java | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 2cf5f57bfde2..451b88b65a9b 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -379,8 +379,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren multipleSelectionLabel.setVerticalAlignment(SwingConstants.TOP); multipleSelectionLabel.setBorder(IdeBorderFactory.createEmptyBorder(5, 7, 0, 0)); mySplitter.setSecondComponent(multipleSelectionLabel); - } else { - showInRightPanel(null); + } + else { + showInRightPanel(myTree.getCommonSelectedElement()); } } else { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java index f3f53e2a9ef8..ce47e3fff67f 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java @@ -128,6 +128,36 @@ public class InspectionTree extends Tree { return toolWrapper; } + @Nullable + public RefEntity getCommonSelectedElement() { + final Object node = getCommonSelectedNode(); + return node instanceof RefElementNode ? ((RefElementNode)node).getElement() : null; + } + + @Nullable + private Object getCommonSelectedNode() { + final TreePath[] paths = getSelectionPaths(); + if (paths == null) return null; + final Object[][] resolvedPaths = new Object[paths.length][]; + for (int i = 0; i < paths.length; i++) { + TreePath path = paths[i]; + resolvedPaths[i] = path.getPath(); + } + + Object currentCommonNode = null; + for (int i = 0; i < resolvedPaths[0].length; i++) { + final Object currentNode = resolvedPaths[0][i]; + for (int j = 1; j < resolvedPaths.length; j++) { + final Object o = resolvedPaths[j][i]; + if (!o.equals(currentNode)) { + return currentCommonNode; + } + } + currentCommonNode = currentNode; + } + return currentCommonNode; + } + @NotNull public RefEntity[] getSelectedElements() { TreePath[] selectionPaths = getSelectionPaths(); From 141650b573a5f777be9b1229823ac3230bb7a1ff Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 16 Feb 2016 12:50:59 +0300 Subject: [PATCH 32/84] inspections tool window: reuse preview editor for same file to prevent selection jumping --- .../ui/InspectionResultsView.java | 47 ++++++++++++++----- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 451b88b65a9b..a0cf0c2fd653 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -43,6 +43,7 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindowId; @@ -86,6 +87,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private static final Logger LOG = Logger.getInstance(InspectionResultsView.class); public static final DataKey DATA_KEY = DataKey.create("inspectionView"); + private static final Key PREVIEW_EDITOR_IS_REUSED_KEY = Key.create("inspection.tool.window.preview.editor.is.reused."); private final Project myProject; private final InspectionTree myTree; @@ -372,7 +374,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } private void syncRightPanel() { - releaseEditor(); + final Editor oldEditor = myPreviewEditor; if (myTree.getSelectionModel().getSelectionCount() != 1) { if (myTree.getSelectedToolWrapper() == null) { final JLabel multipleSelectionLabel = new JBLabel(InspectionViewNavigationPanel.getTitleText(false, false)); @@ -415,6 +417,14 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } } } + if (oldEditor != null) { + if (Boolean.TRUE.equals(oldEditor.getUserData(PREVIEW_EDITOR_IS_REUSED_KEY))) { + oldEditor.putUserData(PREVIEW_EDITOR_IS_REUSED_KEY, null); + } + else { + releaseEditor(); + } + } } private void showInRightPanel(@Nullable final RefEntity refEntity) { @@ -426,10 +436,12 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren CommonProblemDescriptor[] descriptors = myTree.getSelectedDescriptors(); editorPanel.add(createBaseRightComponentFor(descriptors, refEntity), BorderLayout.CENTER); if (descriptors.length > 0) { + final InspectionToolWrapper tool = myTree.getSelectedToolWrapper(); + LOG.assertTrue(tool != null); editorPanel.add(new QuickFixToolbar(myTree, myProject, myPreviewEditor, - myProvider.getQuickFixes(myTree.getSelectedToolWrapper(), myTree)), + myProvider.getQuickFixes(tool, myTree)), BorderLayout.NORTH); } mySplitter.setSecondComponent(editorPanel); @@ -439,6 +451,10 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } } + private boolean reuseEditorFor(Document document) { + return myPreviewEditor != null && !myPreviewEditor.isDisposed() && myPreviewEditor.getDocument() == document; + } + private JComponent createBaseRightComponentFor(CommonProblemDescriptor[] descriptors, RefEntity selectedEntity) { final int count = descriptors.length; @@ -455,16 +471,23 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } final PsiFile file = selectedElement.getContainingFile(); final Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); - myPreviewEditor = EditorFactory.getInstance().createEditor(document, myProject, file.getVirtualFile(), true); - final EditorSettings settings = myPreviewEditor.getSettings(); - settings.setLineNumbersShown(false); - settings.setLineMarkerAreaShown(false); - settings.setAdditionalColumnsCount(0); - settings.setAdditionalLinesCount(0); - settings.setLeadingWhitespaceShown(true); - settings.setRightMarginShown(true); - settings.setRightMargin(60); - UsagePreviewPanel.highlight(Collections.emptyList(), myPreviewEditor, myProject); + + if (reuseEditorFor(document)) { + myPreviewEditor.putUserData(PREVIEW_EDITOR_IS_REUSED_KEY, true); + } + else { + myPreviewEditor = EditorFactory.getInstance().createEditor(document, myProject, file.getVirtualFile(), true); + final EditorSettings settings = myPreviewEditor.getSettings(); + settings.setLineNumbersShown(false); + settings.setLineMarkerAreaShown(false); + settings.setAdditionalColumnsCount(0); + settings.setAdditionalLinesCount(0); + settings.setLeadingWhitespaceShown(true); + settings.setRightMarginShown(true); + settings.setRightMargin(60); + UsagePreviewPanel.highlight(Collections.emptyList(), myPreviewEditor, myProject); + } + if (count == 1) { final PsiElement finalSelectedElement = selectedElement; ApplicationManager.getApplication().invokeLater(() -> { From 2738ceea320e9e37ecb6dc7be9534210196cb524 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 16 Feb 2016 13:02:45 +0300 Subject: [PATCH 33/84] inspections tool window: prev/next occurrences visibility fixed --- .../occurrences/GoToSubsequentOccurrenceAction.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java index eca22402d973..7c9ddf75459a 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/actions/occurrences/GoToSubsequentOccurrenceAction.java @@ -17,8 +17,6 @@ package com.intellij.codeInspection.ui.actions.occurrences; import com.intellij.codeInspection.CommonProblemDescriptor; import com.intellij.codeInspection.ProblemDescriptorBase; -import com.intellij.codeInspection.reference.RefElement; -import com.intellij.codeInspection.reference.RefEntity; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.AnAction; @@ -26,18 +24,13 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.stream.Collectors; /** * @author Dmitry Batkovich @@ -114,6 +107,9 @@ public class GoToSubsequentOccurrenceAction extends AnAction { } public boolean hasValidSubsequent() { + if (myEditor.isDisposed()) { + return false; + } int subsequentIdz = mySelected; while (true) { subsequentIdz += 1 + myChildren.length; From a3a96fe03d6d8d2995e64cf08c111db32845065b Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 16 Feb 2016 14:14:56 +0300 Subject: [PATCH 34/84] inspections tool window: reused editor release fixed --- .../codeInspection/ui/InspectionResultsView.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index a0cf0c2fd653..38b30a60c140 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -332,7 +332,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren @Override public void dispose() { - releaseEditor(); + releaseEditor(myPreviewEditor); mySplitter.dispose(); myInspectionProfile = null; myDisposed = true; @@ -422,7 +422,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren oldEditor.putUserData(PREVIEW_EDITOR_IS_REUSED_KEY, null); } else { - releaseEditor(); + releaseEditor(oldEditor); } } } @@ -967,10 +967,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren return Collections.singletonList(new UsageInfo(element)); } - private void releaseEditor() { - if (myPreviewEditor != null) { - EditorFactory.getInstance().releaseEditor(myPreviewEditor); - myPreviewEditor = null; + private static void releaseEditor(@Nullable Editor editor) { + if (editor != null && !editor.isDisposed()) { + EditorFactory.getInstance().releaseEditor(editor); } } } From 9ae4ba004f55613dc1a65475187c61f10757dc4a Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 16 Feb 2016 14:15:31 +0300 Subject: [PATCH 35/84] inspections tool window: unused method deleted --- .../codeInspection/ui/InspectionResultsView.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 38b30a60c140..d12532deaecf 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -956,17 +956,6 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } } - @NotNull - private static List getElementToHighlight(@Nullable PsiElement element) { - if (element instanceof PsiFile || element == null) { - return Collections.emptyList(); - } - if (element instanceof PsiNameIdentifierOwner) { - return getElementToHighlight(((PsiNameIdentifierOwner)element).getNameIdentifier()); - } - return Collections.singletonList(new UsageInfo(element)); - } - private static void releaseEditor(@Nullable Editor editor) { if (editor != null && !editor.isDisposed()) { EditorFactory.getInstance().releaseEditor(editor); From 183a70137b92c622139ee992480aeeac1d193316 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 16 Feb 2016 14:17:13 +0300 Subject: [PATCH 36/84] inspections tool window: cleanup --- .../com/intellij/codeInspection/ui/InspectionResultsView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index d12532deaecf..553de2bbf0b1 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -87,7 +87,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private static final Logger LOG = Logger.getInstance(InspectionResultsView.class); public static final DataKey DATA_KEY = DataKey.create("inspectionView"); - private static final Key PREVIEW_EDITOR_IS_REUSED_KEY = Key.create("inspection.tool.window.preview.editor.is.reused."); + private static final Key PREVIEW_EDITOR_IS_REUSED_KEY = Key.create("inspection.tool.window.preview.editor.is.reused."); private final Project myProject; private final InspectionTree myTree; From d822f197ae840070ff4c19df765ded0b0f3173b5 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 16 Feb 2016 14:39:48 +0300 Subject: [PATCH 37/84] inspections tool window: properly show text on multiple apply fix button --- .../codeInspection/ex/DescriptorComposer.java | 2 +- .../codeInspection/ex/LocalQuickFixWrapper.java | 12 ++---------- .../intellij/codeInspection/ex/QuickFixAction.java | 2 +- .../ui/DefaultInspectionToolPresentation.java | 14 +++++++++++++- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorComposer.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorComposer.java index b9f2be991410..c94884f1d527 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorComposer.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorComposer.java @@ -81,7 +81,7 @@ public class DescriptorComposer extends HTMLComposerImpl { } List texts = new ArrayList(); for (QuickFixAction quickFix : quickFixes) { - String text = quickFix.getText(where); + String text = quickFix.getText(); if (text == null) continue; texts.add(escapeQuickFixText(text)); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/LocalQuickFixWrapper.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/LocalQuickFixWrapper.java index 278f1f51b9aa..18342b16befe 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/LocalQuickFixWrapper.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/LocalQuickFixWrapper.java @@ -40,28 +40,20 @@ import java.util.Set; */ public class LocalQuickFixWrapper extends QuickFixAction { private final QuickFix myFix; - private String myText; public LocalQuickFixWrapper(@NotNull QuickFix fix, @NotNull InspectionToolWrapper toolWrapper) { super(fix.getName(), toolWrapper); myFix = fix; - myText = myFix.getName(); + setText(myFix.getName()); } @Override public void update(AnActionEvent e) { super.update(e); - getTemplatePresentation().setText(myText); - e.getPresentation().setText(myText); - } - - @Override - public String getText(RefEntity where) { - return myText; } public void setText(@NotNull String text) { - myText = text; + getTemplatePresentation().setText(text); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java index 29fe06ddf186..abd82c1a8789 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java @@ -101,7 +101,7 @@ public class QuickFixAction extends AnAction { return false; } - public String getText(RefEntity where) { + public String getText() { return getTemplatePresentation().getText(); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java index 75386d442fbe..cc87a9c5bd14 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java @@ -652,10 +652,10 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro @Nullable CommonProblemDescriptor[] allowedDescriptors) { final Set allowedDescriptorSet = allowedDescriptors == null ? null : ContainerUtil.newHashSet(allowedDescriptors); Map result = new com.intellij.util.containers.HashMap<>(); + boolean isFirst = true; for (RefEntity refElement : refElements) { final CommonProblemDescriptor[] descriptors = descriptorMap.get(refElement); if (descriptors == null) continue; - boolean isFirst = true; for (CommonProblemDescriptor d : descriptors) { if (allowedDescriptorSet != null && !allowedDescriptorSet.contains(d)) { continue; @@ -679,6 +679,18 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro final Class klass = getFixClass(fix); if (clazz.equals(klass)) { isFound = true; + final QuickFixAction quickFixAction = result.get(clazz); + try { + String familyName = fix.getFamilyName(); + familyName = !familyName.isEmpty() ? "\'" + familyName + "\'" : familyName; + ((LocalQuickFixWrapper)quickFixAction) + .setText(InspectionsBundle.message("inspection.descriptor.provider.apply.fix", familyName)); + } + catch (AbstractMethodError e) { + //for plugin compatibility + ((LocalQuickFixWrapper)quickFixAction) + .setText(InspectionsBundle.message("inspection.descriptor.provider.apply.fix", "")); + } break; } } From 2eb92a2374524dd5c8658916444374c0625bb5bd Mon Sep 17 00:00:00 2001 From: "Svetlana.Zemlyanskaya" Date: Fri, 5 Feb 2016 10:22:24 +0100 Subject: [PATCH 38/84] Remote Interpreters: add path mappings to python (cherry picked from commit b0e41df) --- .../PyActiveSdkConfigurable.java | 20 +++++++-- python/src/META-INF/python-core-common.xml | 1 + .../com/jetbrains/python/PyBundle.properties | 2 + .../python/sdk/PyCustomSdkUiProvider.java | 44 +++++++++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 python/src/com/jetbrains/python/sdk/PyCustomSdkUiProvider.java diff --git a/python/python-community-configure/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/python-community-configure/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index f8124626d520..df01a1c3130d 100644 --- a/python/python-community-configure/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/python-community-configure/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -15,6 +15,7 @@ */ package com.jetbrains.python.configuration; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.ConfigurationException; @@ -31,6 +32,7 @@ import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.FixedSizeButton; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.CollectionComboBoxModel; @@ -71,6 +73,8 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { private static final String SHOW_ALL = PyBundle.message("active.sdk.dialog.show.all.item"); private Set myInitialSdkSet; + private Disposable myDisposable = null; + public PyActiveSdkConfigurable(@NotNull Project project) { myModule = null; myProject = project; @@ -149,14 +153,21 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { c.weightx = 0.0; myMainPanel.add(myDetailsButton, c); + final PyCustomSdkUiProvider customUiProvider = PyCustomSdkUiProvider.getInstance(); + if (customUiProvider != null) { + myDisposable = Disposer.newDisposable(); + customUiProvider.customizeActiveSdkPanel(myProject, mySdkCombo, myMainPanel, c, myDisposable); + } + c.insets = new Insets(2,2,0,2); c.gridx = 0; - c.gridy = 1; + c.gridy++; c.gridwidth = 3; + c.weightx = 0.0; myMainPanel.add(emptyLabel, c); c.gridx = 0; - c.gridy = 2; + c.gridy++; c.weighty = 1.; c.gridwidth = 3; c.gridheight = GridBagConstraints.RELATIVE; @@ -165,7 +176,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { c.gridheight = GridBagConstraints.REMAINDER; c.gridx = 0; - c.gridy = 3; + c.gridy++; c.gridwidth = 3; c.weighty = 0.; c.fill = GridBagConstraints.HORIZONTAL; @@ -374,6 +385,9 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { public void disposeUIResources() { myProjectSdksModel.removeListener(mySdkModelListener); myInterpreterList.disposeModel(); + if (myDisposable != null) { + Disposer.dispose(myDisposable); + } } private class MySdkModelListener implements SdkModel.Listener { diff --git a/python/src/META-INF/python-core-common.xml b/python/src/META-INF/python-core-common.xml index d4ce10ae8af3..30bb68914ed7 100644 --- a/python/src/META-INF/python-core-common.xml +++ b/python/src/META-INF/python-core-common.xml @@ -611,6 +611,7 @@ + diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index da279f743a53..51fd13b7e041 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -890,6 +890,8 @@ sdk.gen.stubs.for.binary.modules=Generate stubs for binary module {0} # Active SDK configurable and related dialogs active.sdk.dialog.show.all.item=Show All active.sdk.dialog.project.interpreter=Project Interpreter: +active.sdk.dialog.project.interpreter.path.mappings=Path mappings: +active.sdk.dialog.project.interpreter.path.mappings.default.project.error=Open or create project to configure mappings sdk.details.step.add.local=Add Local sdk.details.step.add.remote=Add Remote diff --git a/python/src/com/jetbrains/python/sdk/PyCustomSdkUiProvider.java b/python/src/com/jetbrains/python/sdk/PyCustomSdkUiProvider.java new file mode 100644 index 000000000000..350b6d190613 --- /dev/null +++ b/python/src/com/jetbrains/python/sdk/PyCustomSdkUiProvider.java @@ -0,0 +1,44 @@ +/* + * 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. + */ +package com.jetbrains.python.sdk; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ComboBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; + +public abstract class PyCustomSdkUiProvider { + public final static ExtensionPointName EP_NAME = + ExtensionPointName.create("Pythonid.pyCustomSdkUiProvider"); + + @Nullable + public static PyCustomSdkUiProvider getInstance() { + if (EP_NAME.getExtensions().length > 0) { + return EP_NAME.getExtensions()[0]; + } + else { + return null; + } + } + + public abstract void customizeActiveSdkPanel(@NotNull Project project, @NotNull ComboBox mySdkCombo, @NotNull JPanel myMainPanel, + @NotNull GridBagConstraints c, @NotNull Disposable disposable); +} From 86fc8980c3d42e6dfd80cea528ecf3eeafecab24 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Tue, 16 Feb 2016 19:47:00 +0300 Subject: [PATCH 39/84] IDEA-151765 HiDPI display: small code analysis icons in the editor --- .../com/intellij/codeHighlighting/HighlightDisplayLevel.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/analysis-api/src/com/intellij/codeHighlighting/HighlightDisplayLevel.java b/platform/analysis-api/src/com/intellij/codeHighlighting/HighlightDisplayLevel.java index 5a19b1271032..ff9971630250 100644 --- a/platform/analysis-api/src/com/intellij/codeHighlighting/HighlightDisplayLevel.java +++ b/platform/analysis-api/src/com/intellij/codeHighlighting/HighlightDisplayLevel.java @@ -180,7 +180,9 @@ public class HighlightDisplayLevel { @Override public void paintIcon(Component c, Graphics g, int x, int y) { g.setColor(getColor()); - g.fillRect(x + 2, y + 2, 10, 10); + int shift = JBUI.scale(2); + int size = JBUI.scale(10); + g.fillRect(x + shift, y + shift, size, size); } @Override From eb6aee1e8befaf03259efb3f3e34941c06a24b01 Mon Sep 17 00:00:00 2001 From: "Dmitry.Krasilschikov" Date: Tue, 16 Feb 2016 20:02:08 +0300 Subject: [PATCH 40/84] #RUBY-17804 #IDEA-CR-8480 fix add empty project to project wizard --- .../ide/util/projectWizard/AbstractNewProjectStep.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/projectWizard/AbstractNewProjectStep.java b/platform/lang-impl/src/com/intellij/ide/util/projectWizard/AbstractNewProjectStep.java index 29e35201fcbb..bb56047a0422 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/projectWizard/AbstractNewProjectStep.java +++ b/platform/lang-impl/src/com/intellij/ide/util/projectWizard/AbstractNewProjectStep.java @@ -57,8 +57,7 @@ public class AbstractNewProjectStep extends DefaultActionGroup implements DumbAw NullableConsumer callback = customization.createCallback(); ProjectSpecificAction projectSpecificAction = customization.createProjectSpecificAction(callback); - - addAll(projectSpecificAction.getChildren(null)); + addProjectSpecificAction(projectSpecificAction); DirectoryProjectGenerator[] generators = customization.getProjectGenerators(); customization.setUpBasicAction(projectSpecificAction, generators); @@ -67,6 +66,10 @@ public class AbstractNewProjectStep extends DefaultActionGroup implements DumbAw addAll(customization.getExtraActions(callback)); } + protected void addProjectSpecificAction(@NotNull final ProjectSpecificAction projectSpecificAction) { + addAll(projectSpecificAction.getChildren(null)); + } + protected static abstract class Customization { @NotNull protected ProjectSpecificAction createProjectSpecificAction(@NotNull final NullableConsumer callback) { From ff1f8427402ebe078483327290084d02e763adc1 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Tue, 16 Feb 2016 20:04:01 +0300 Subject: [PATCH 41/84] [vcs-log] minor: rename UI -> ui, myUI -> myUi --- .../vcs/log/ui/frame/BranchesPanel.java | 10 +++++----- .../vcs/log/ui/frame/VcsLogGraphTable.java | 20 +++++++++---------- .../vcs/log/ui/tables/GraphTableModel.java | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java index de0f93728497..0c62639d7d86 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java @@ -35,20 +35,20 @@ public class BranchesPanel extends JPanel { private static final int TOP = 2; private static final int BOTTOM = 3; @NotNull private final VcsLogDataHolder myDataHolder; - @NotNull private final VcsLogUiImpl myUI; + @NotNull private final VcsLogUiImpl myUi; @NotNull private final VcsRefPainter myReferencePainter; @NotNull private LinkedHashMap> myRefGroups; @Nullable private Collection myRoots = null; - public BranchesPanel(@NotNull VcsLogDataHolder dataHolder, @NotNull VcsLogUiImpl UI, @NotNull RefsModel initialRefsModel) { + public BranchesPanel(@NotNull VcsLogDataHolder dataHolder, @NotNull VcsLogUiImpl ui, @NotNull RefsModel initialRefsModel) { super(new FlowLayout(FlowLayout.LEADING, BIG_ROOTS_GAP - 2 * SMALL_ROOTS_GAP, 0)); setBorder(new EmptyBorder(TOP, SMALL_ROOTS_GAP, BOTTOM, SMALL_ROOTS_GAP)); myDataHolder = dataHolder; - myUI = UI; + myUi = ui; myRefGroups = getRefsToDisplayOnPanel(initialRefsModel); - myReferencePainter = new VcsRefPainter(myUI.getColorManager(), true); + myReferencePainter = new VcsRefPainter(myUi.getColorManager(), true); recreateComponents(); } @@ -129,7 +129,7 @@ public class BranchesPanel extends JPanel { myGroups = groups; for (RefGroup group : myGroups) { - add(new ReferenceGroupComponent(group, myReferencePainter, myUI, root)); + add(new ReferenceGroupComponent(group, myReferencePainter, myUi, root)); } } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java index ff1335f7b534..4d3f9c58d8b7 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java @@ -83,7 +83,7 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi private static final int MAX_ROWS_TO_CALC_WIDTH = 1000; private static final int MAX_ROWS_TO_CALC_OFFSET = 100; - @NotNull private final VcsLogUiImpl myUI; + @NotNull private final VcsLogUiImpl myUi; private final VcsLogDataHolder myLogDataHolder; private final MyDummyTableCellEditor myDummyEditor = new MyDummyTableCellEditor(); @NotNull private final TableCellRenderer myDummyRenderer = new DefaultTableCellRenderer(); @@ -104,13 +104,13 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi } }; - public VcsLogGraphTable(@NotNull VcsLogUiImpl UI, @NotNull final VcsLogDataHolder logDataHolder, @NotNull VisiblePack initialDataPack) { + public VcsLogGraphTable(@NotNull VcsLogUiImpl ui, @NotNull final VcsLogDataHolder logDataHolder, @NotNull VisiblePack initialDataPack) { super(); - myUI = UI; + myUi = ui; myLogDataHolder = logDataHolder; myGraphCommitCellRenderer = new GraphCommitCellRender(logDataHolder, myGraphCellPainter, this); - setDefaultRenderer(VirtualFile.class, new RootCellRenderer(myUI)); + setDefaultRenderer(VirtualFile.class, new RootCellRenderer(myUi)); setDefaultRenderer(GraphCommitCell.class, myGraphCommitCellRenderer); setDefaultRenderer(String.class, new StringCellRenderer()); @@ -125,7 +125,7 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi PopupHandler.installPopupHandler(this, VcsLogActionPlaces.POPUP_ACTION_GROUP, VcsLogActionPlaces.VCS_LOG_TABLE_PLACE); ScrollingUtil.installActions(this, false); - GraphTableModel model = new GraphTableModel(initialDataPack, myLogDataHolder, myUI); + GraphTableModel model = new GraphTableModel(initialDataPack, myLogDataHolder, myUi); setModel(model); initColumnSize(); } @@ -193,10 +193,10 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi private void setRootColumnSize(TableColumn column) { int rootWidth; - if (!myUI.isMultipleRoots()) { + if (!myUi.isMultipleRoots()) { rootWidth = 0; } - else if (!myUI.isShowRootNames()) { + else if (!myUi.isShowRootNames()) { rootWidth = ROOT_INDICATOR_WIDTH; } else { @@ -231,7 +231,7 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi return "" + ((VirtualFile)at).getPresentableUrl() + "
Click to " + - (myUI.isShowRootNames() ? "collapse" : "expand") + + (myUi.isShowRootNames() ? "collapse" : "expand") + ""; } } @@ -363,7 +363,7 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi private boolean expandOrCollapseRoots(@NotNull MouseEvent e) { TableColumn column = getRootColumnOrNull(e); if (column != null) { - myUI.setShowRootNames(!myUI.isShowRootNames()); + myUi.setShowRootNames(!myUi.isShowRootNames()); return true; } return false; @@ -400,7 +400,7 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi } } - myUI.repaintUI(); // in case of repaintUI doing something more than just repainting this table in some distant future + myUi.repaintUI(); // in case of repaintUI doing something more than just repainting this table in some distant future if (answer == null) { return; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java index f0177df4a6d0..8631ba5e0515 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java @@ -45,9 +45,9 @@ public class GraphTableModel extends AbstractTableModel { private boolean myMoreRequested; - public GraphTableModel(@NotNull VisiblePack dataPack, @NotNull VcsLogDataHolder dataHolder, @NotNull VcsLogUiImpl UI) { + public GraphTableModel(@NotNull VisiblePack dataPack, @NotNull VcsLogDataHolder dataHolder, @NotNull VcsLogUiImpl ui) { myLogDataHolder = dataHolder; - myUi = UI; + myUi = ui; myDataPack = dataPack; myDataHolder = dataHolder; } From 8fdf37e038a20bf3efb96be53f8cd39509e581a3 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 16 Feb 2016 17:24:42 +0100 Subject: [PATCH 42/84] inference: skip unchecked warning for types based on inference variables (IDEA-151761) --- .../constraints/TypeCompatibilityConstraint.java | 2 +- ...UncheckedWarningConvertingToInferenceVariable.java | 11 +++++++++++ .../daemon/lambda/GraphInferenceHighlightingTest.java | 4 ++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedWarningConvertingToInferenceVariable.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeCompatibilityConstraint.java index f86c78c2726a..368431f65696 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeCompatibilityConstraint.java @@ -75,7 +75,7 @@ public class TypeCompatibilityConstraint implements ConstraintFormula { final PsiClassType.ClassResolveResult sResult = ((PsiClassType)s).resolveGenerics(); final PsiClass tClass = tResult.getElement(); final PsiClass sClass = sResult.getElement(); - if (tClass != null && sClass != null) { + if (tClass != null && sClass != null && !(sClass instanceof InferenceVariable)) { final PsiSubstitutor sSubstitutor = TypeConversionUtil.getClassSubstitutor(tClass, sClass, sResult.getSubstitutor()); if (sSubstitutor != null) { if (PsiUtil.isRawSubstitutor(tClass, sSubstitutor)) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedWarningConvertingToInferenceVariable.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedWarningConvertingToInferenceVariable.java new file mode 100644 index 000000000000..9f8d7029043a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedWarningConvertingToInferenceVariable.java @@ -0,0 +1,11 @@ +import java.util.List; + +class Test { + void m(Class clazz){ + List data = foo(clazz); + } + + public static T foo(Class clazz) { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java index 9544b9e6ed87..e71ad2e341ee 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java @@ -379,6 +379,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase doTest(); } + public void testUncheckedWarningConvertingToInferenceVariable() throws Exception { + doTest(); + } + private void doTest() throws Exception { doTest(false); } From 7dd0db8963806a675ab7a38a6f6152210d851dd2 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 16 Feb 2016 17:50:32 +0100 Subject: [PATCH 43/84] captured wildcard: access object should be placed to the same package (IDEA-151766) --- java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java | 7 ++++++- .../CapturedWildcardPackageLocalAccess.java | 8 ++++++++ .../daemon/lambda/GenericsHighlighting8Test.java | 4 ++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CapturedWildcardPackageLocalAccess.java diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java index 1602daa653e1..bd702c64f57a 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java @@ -24,6 +24,7 @@ import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; @@ -123,7 +124,11 @@ public final class PsiUtil extends PsiUtilCore { if (type instanceof PsiCapturedWildcardType) { final PsiType upperBound = ((PsiCapturedWildcardType)type).getUpperBound(); if (upperBound instanceof PsiClassType) { - String classText = "class I {}"; + final PsiClass resolved = ((PsiClassType)upperBound).resolve(); + final PsiFile containingFile = resolved != null ? resolved.getContainingFile() : null; + final String packageName = containingFile instanceof PsiClassOwner ? ((PsiClassOwner)containingFile).getPackageName() : null; + String classText = StringUtil.isEmptyOrSpaces(packageName) ? "" : "package " +packageName + ";\n "; + classText += "class I {}"; final PsiJavaFile file = (PsiJavaFile)PsiFileFactory.getInstance(expression.getProject()).createFileFromText("inference_dummy.java", JavaLanguage.INSTANCE, classText); final PsiTypeParameter freshParameter = file.getClasses()[0].getTypeParameters()[0]; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CapturedWildcardPackageLocalAccess.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CapturedWildcardPackageLocalAccess.java new file mode 100644 index 000000000000..edea5438c654 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CapturedWildcardPackageLocalAccess.java @@ -0,0 +1,8 @@ +import java.util.Map; + +class Test { + void f() {} + void m(Map map, String name) { + map.get(name).f(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java index 5b7d17ee603c..ae6977d8a644 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java @@ -966,4 +966,8 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase { public void testCapturedWildcardWithPrimitiveTypesChecks() throws Exception { doTest(); } + + public void testCapturedWildcardPackageLocalAccess() throws Exception { + doTest(); + } } From 0a17e681ebceb4a85f35c3a250f30840103988fc Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 16 Feb 2016 18:08:31 +0100 Subject: [PATCH 44/84] testng: fix filtering according to selected params (IDEA-151744) --- plugins/testng_rt/src/org/testng/IDEARemoteTestNG.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/testng_rt/src/org/testng/IDEARemoteTestNG.java b/plugins/testng_rt/src/org/testng/IDEARemoteTestNG.java index 3d43424974f0..85e8c97bfaf6 100644 --- a/plugins/testng_rt/src/org/testng/IDEARemoteTestNG.java +++ b/plugins/testng_rt/src/org/testng/IDEARemoteTestNG.java @@ -22,6 +22,7 @@ import org.testng.xml.XmlInclude; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -53,10 +54,11 @@ public class IDEARemoteTestNG extends TestNG { try { if (myParam != null) { for (XmlClass aClass : test.getXmlClasses()) { + List includes = new ArrayList(); for (XmlInclude include : aClass.getIncludedMethods()) { - final XmlInclude xmlInclude = new XmlInclude(include.getName(), Collections.singletonList(Integer.parseInt(myParam)), 0); - aClass.setIncludedMethods(Collections.singletonList(xmlInclude)); + includes.add(new XmlInclude(include.getName(), Collections.singletonList(Integer.parseInt(myParam)), 0)); } + aClass.setIncludedMethods(includes); } } } From 3a08734b1571b8918bc4330a1062dc5b104087ee Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Tue, 16 Feb 2016 20:00:20 +0300 Subject: [PATCH 45/84] Store task and answer placeholder StudyStatus in class instances Leave status maps in order to provide backward compatibility with study project Add Uninitialized StudyStatus indicating the old project Now in project generation all statuses ara initialized with Unchecked StudyStatus --- .../edu/courseFormat/AnswerPlaceholder.java | 11 ++++++ .../edu/courseFormat/StudyStatus.java | 2 +- .../com/jetbrains/edu/courseFormat/Task.java | 10 ++++++ .../edu/learning/StudyTaskManager.java | 35 ++++++++++--------- 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/python/educational-core/src/com/jetbrains/edu/courseFormat/AnswerPlaceholder.java b/python/educational-core/src/com/jetbrains/edu/courseFormat/AnswerPlaceholder.java index ae3230b5e980..979013f97076 100644 --- a/python/educational-core/src/com/jetbrains/edu/courseFormat/AnswerPlaceholder.java +++ b/python/educational-core/src/com/jetbrains/edu/courseFormat/AnswerPlaceholder.java @@ -23,13 +23,16 @@ public class AnswerPlaceholder { private int myIndex = -1; private String myTaskText; private MyInitialState myInitialState; + private StudyStatus myStatus = StudyStatus.Uninitialized; @Transient private TaskFile myTaskFile; public void initAnswerPlaceholder(final TaskFile file, boolean isRestarted) { if (!isRestarted) { setInitialState(new MyInitialState(getLine(), getLength(), getStart())); + myStatus = file.getTask().getStatus(); } + setTaskFile(file); } @@ -136,6 +139,14 @@ public class AnswerPlaceholder { length = myInitialState.myLength; } + public StudyStatus getStatus() { + return myStatus; + } + + public void setStatus(StudyStatus status) { + myStatus = status; + } + public static class MyInitialState { public int myLine = -1; public int myLength = -1; diff --git a/python/educational-core/src/com/jetbrains/edu/courseFormat/StudyStatus.java b/python/educational-core/src/com/jetbrains/edu/courseFormat/StudyStatus.java index 767a3c9fdeb7..e8c11503f565 100644 --- a/python/educational-core/src/com/jetbrains/edu/courseFormat/StudyStatus.java +++ b/python/educational-core/src/com/jetbrains/edu/courseFormat/StudyStatus.java @@ -1,5 +1,5 @@ package com.jetbrains.edu.courseFormat; public enum StudyStatus { - Unchecked, Solved, Failed + Unchecked, Solved, Failed, Uninitialized } diff --git a/python/educational-core/src/com/jetbrains/edu/courseFormat/Task.java b/python/educational-core/src/com/jetbrains/edu/courseFormat/Task.java index e98905dcb4bb..b20ea6374ae1 100644 --- a/python/educational-core/src/com/jetbrains/edu/courseFormat/Task.java +++ b/python/educational-core/src/com/jetbrains/edu/courseFormat/Task.java @@ -24,6 +24,7 @@ public class Task implements StudyItem { // index is visible to user number of task from 1 to task number private int myIndex; + private StudyStatus myStatus = StudyStatus.Uninitialized; private int myStepicId; @@ -49,6 +50,7 @@ public class Task implements StudyItem { */ public void initTask(final Lesson lesson, boolean isRestarted) { setLesson(lesson); + if (!isRestarted) myStatus = StudyStatus.Unchecked; for (TaskFile taskFile : getTaskFiles().values()) { taskFile.initTaskFile(this, isRestarted); } @@ -204,4 +206,12 @@ public class Task implements StudyItem { public int getStepicId() { return myStepicId; } + + public StudyStatus getStatus() { + return myStatus; + } + + public void setStatus(StudyStatus status) { + myStatus = status; + } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java index de23e2ec4288..afd86b186c46 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java @@ -34,10 +34,10 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb private Course myCourse; private OldCourse myOldCourse; public int VERSION = 2; - public Map myStudyStatusMap = new HashMap(); - public Map myTaskStatusMap = new HashMap(); - public Map> myUserTests = new HashMap>(); - public List myInvisibleFiles = new ArrayList(); + public Map myStudyStatusMap = new HashMap<>(); + public Map myTaskStatusMap = new HashMap<>(); + public Map> myUserTests = new HashMap<>(); + public List myInvisibleFiles = new ArrayList<>(); private StudyTaskManager() { } @@ -52,16 +52,13 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb } public void setStatus(AnswerPlaceholder placeholder, StudyStatus status) { - if (myStudyStatusMap == null) { - myStudyStatusMap = new HashMap(); - } - myStudyStatusMap.put(placeholder, status); + placeholder.setStatus(status); } public void addUserTest(@NotNull final Task task, UserTest userTest) { List userTests = myUserTests.get(task); if (userTests == null) { - userTests = new ArrayList(); + userTests = new ArrayList<>(); myUserTests.put(task, userTests); } userTests.add(userTest); @@ -86,29 +83,27 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb public void setStatus(Task task, StudyStatus status) { + task.setStatus(status); for (TaskFile taskFile : task.getTaskFiles().values()) { setStatus(taskFile, status); } } public void setStatus(TaskFile file, StudyStatus status) { - if (file.getAnswerPlaceholders().isEmpty()) { - if (myTaskStatusMap == null) { - myTaskStatusMap = new HashMap(); - } - myTaskStatusMap.put(file, status); - } for (AnswerPlaceholder answerPlaceholder : file.getAnswerPlaceholders()) { setStatus(answerPlaceholder, status); } } public StudyStatus getStatus(AnswerPlaceholder placeholder) { - StudyStatus status = myStudyStatusMap.get(placeholder); + StudyStatus status = placeholder.getStatus(); + if (status != StudyStatus.Uninitialized) return status; + + status = myStudyStatusMap.get(placeholder); if (status == null) { status = StudyStatus.Unchecked; - myStudyStatusMap.put(placeholder, status); } + placeholder.setStatus(status); return status; } @@ -124,15 +119,21 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb } public StudyStatus getStatus(@NotNull final Task task) { + StudyStatus taskStatus = task.getStatus(); + if (taskStatus != StudyStatus.Uninitialized) return taskStatus; + for (TaskFile taskFile : task.getTaskFiles().values()) { StudyStatus taskFileStatus = getStatus(taskFile); if (taskFileStatus == StudyStatus.Unchecked) { + task.setStatus(StudyStatus.Unchecked); return StudyStatus.Unchecked; } if (taskFileStatus == StudyStatus.Failed) { + task.setStatus(StudyStatus.Failed); return StudyStatus.Failed; } } + task.setStatus(StudyStatus.Solved); return StudyStatus.Solved; } From bf226f58ab2945a932c85000d9c5351c9fc37869 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 16 Feb 2016 18:56:06 +0100 Subject: [PATCH 46/84] move members: conflict against members of superclass (IDEA-151440) --- .../move/moveMembers/MoveJavaMemberHandler.java | 13 +++---------- .../moveMembers/existingFieldInSuper/after/A.java | 12 ++++++++++++ .../moveMembers/existingFieldInSuper/after/B.java | 6 ++++++ .../moveMembers/existingFieldInSuper/before/A.java | 12 ++++++++++++ .../moveMembers/existingFieldInSuper/before/B.java | 6 ++++++ .../com/intellij/refactoring/MoveMembersTest.java | 11 +++++++++++ 6 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/after/A.java create mode 100644 java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/after/B.java create mode 100644 java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/before/A.java create mode 100644 java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/before/B.java diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java index 950532ebe61b..43bcfcc7d455 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java @@ -143,7 +143,7 @@ public class MoveJavaMemberHandler implements MoveMemberHandler { } protected static boolean hasMethod(PsiClass targetClass, PsiMethod method) { - PsiMethod[] targetClassMethods = targetClass.getMethods(); + PsiMethod[] targetClassMethods = targetClass.findMethodsByName(method.getName(), true); for (PsiMethod candidate : targetClassMethods) { if (candidate != method && MethodSignatureUtil.areSignaturesEqual(method.getSignature(PsiSubstitutor.EMPTY), @@ -155,15 +155,8 @@ public class MoveJavaMemberHandler implements MoveMemberHandler { } protected static boolean hasField(PsiClass targetClass, PsiField field) { - String fieldName = field.getName(); - PsiField[] targetClassFields = targetClass.getFields(); - for (PsiField candidate : targetClassFields) { - if (candidate != field && - fieldName.equals(candidate.getName())) { - return true; - } - } - return false; + final PsiField fieldByName = targetClass.findFieldByName(field.getName(), true); + return fieldByName != null && fieldByName != field; } @Override diff --git a/java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/after/A.java b/java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/after/A.java new file mode 100644 index 000000000000..810415096682 --- /dev/null +++ b/java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/after/A.java @@ -0,0 +1,12 @@ +class One { + static boolean truth = true; + static void important() { + System.out.println(1); + } +} +class A extends One { + Two() { + important(); + System.out.println(truth); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/after/B.java b/java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/after/B.java new file mode 100644 index 000000000000..06e97dde4a42 --- /dev/null +++ b/java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/after/B.java @@ -0,0 +1,6 @@ +public class B { + static boolean truth = false; + static void important() { + System.out.println(2); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/before/A.java b/java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/before/A.java new file mode 100644 index 000000000000..1b8822c0e01b --- /dev/null +++ b/java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/before/A.java @@ -0,0 +1,12 @@ +class One { + static boolean truth = true; + static void important() { + System.out.println(1); + } +} +class A extends One { + Two() { + important(); + System.out.println(truth); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/before/B.java b/java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/before/B.java new file mode 100644 index 000000000000..06e97dde4a42 --- /dev/null +++ b/java/java-tests/testData/refactoring/moveMembers/existingFieldInSuper/before/B.java @@ -0,0 +1,6 @@ +public class B { + static boolean truth = false; + static void important() { + System.out.println(2); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/MoveMembersTest.java b/java/java-tests/testSrc/com/intellij/refactoring/MoveMembersTest.java index 51f896f1c9d2..7a8c549adf4b 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/MoveMembersTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/MoveMembersTest.java @@ -154,6 +154,17 @@ public class MoveMembersTest extends MultiFileTestCase { } } + public void testExistingFieldInSuper() throws Exception { + try { + doTest("B", "A", 0, 1); + fail("conflict expected"); + } + catch (BaseRefactoringProcessor.ConflictsInTestsException e) { + assertEquals("Field truth already exists in the target class.\n" + + "Method important() already exists in the target class.", e.getMessage()); + } + } + public void testInnerToInterface() throws Exception { doTest("A", "B", 0); } From 9ef33e1ab4eab298af3b6f81fbdd08146aa2b89d Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Wed, 17 Feb 2016 00:08:13 +0300 Subject: [PATCH 47/84] Skeletons sync --- .../python-skeletons/django/forms/__init__.py | 0 .../python-skeletons/django/forms/forms.py | 22 ++++++++++++++++ .../python-skeletons/django/forms/formsets.py | 25 +++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 python/helpers/python-skeletons/django/forms/__init__.py create mode 100644 python/helpers/python-skeletons/django/forms/forms.py create mode 100644 python/helpers/python-skeletons/django/forms/formsets.py diff --git a/python/helpers/python-skeletons/django/forms/__init__.py b/python/helpers/python-skeletons/django/forms/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/helpers/python-skeletons/django/forms/forms.py b/python/helpers/python-skeletons/django/forms/forms.py new file mode 100644 index 000000000000..9f4b7f794348 --- /dev/null +++ b/python/helpers/python-skeletons/django/forms/forms.py @@ -0,0 +1,22 @@ +from django.forms.forms import BoundField +class BaseForm(object): + """ + This is the main implementation of all the Form logic. Note that this + class is different than Form. See the comments by the Form class for more + information. Any improvements to the form API should be made to *this* + class, not to the Form class. + + """ + + def __iter__(self): + """ + + :rtype: collections.Iterator[BoundField] + """ + pass + + def __getitem__(self, index): + """ + :rtype: BoundField + """ + pass \ No newline at end of file diff --git a/python/helpers/python-skeletons/django/forms/formsets.py b/python/helpers/python-skeletons/django/forms/formsets.py new file mode 100644 index 000000000000..2f229065ce19 --- /dev/null +++ b/python/helpers/python-skeletons/django/forms/formsets.py @@ -0,0 +1,25 @@ +from django.forms import Form +class BaseFormSet(object): + """ + A collection of instances of the same Form class. + + """ + + def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, + initial=None, error_class=ErrorList, form_kwargs=None): + """ + :rtype: BaseFormSet[T <= Form] + """ + + def __iter__(self): + """ + + :rtype: collections.Iterator[T] + """ + pass + + def __getitem__(self, index): + """ + :rtype: T + """ + pass From 85c3e995a5d590023586fb05bdea68601a5603e2 Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Wed, 17 Feb 2016 00:11:32 +0300 Subject: [PATCH 48/84] Django forms and formset support added * "for" django tag supports iteration * django forms and formset typing added * Tests added --- .../python/codeInsight/PyCustomMember.java | 35 +++++++++++- .../codeInsight/PyCustomMemberTypeInfo.java | 55 +++++++++++++++++++ .../nameResolver/NameResolverTools.java | 27 +++++++-- .../psi/impl/PyTargetExpressionImpl.java | 4 +- .../psi/types/PyCollectionTypeImpl.java | 17 +++++- .../jetbrains/python/fixtures/PyTestCase.java | 27 +++++++++ 6 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMemberTypeInfo.java diff --git a/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMember.java b/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMember.java index 543d635050d5..488d6038b997 100644 --- a/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMember.java +++ b/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMember.java @@ -15,6 +15,7 @@ */ package com.jetbrains.python.codeInsight; +import com.google.common.base.Preconditions; import com.intellij.extapi.psi.ASTWrapperPsiElement; import com.intellij.icons.AllIcons; import com.intellij.openapi.util.Key; @@ -27,6 +28,7 @@ import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.psi.PyPsiFacade; import com.jetbrains.python.psi.PyTypedElement; +import com.jetbrains.python.psi.types.PyClassType; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; @@ -35,6 +37,9 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; /** + * Note: if you use {@link #myTypeName} to override real field, be sure to use + * {@link com.jetbrains.python.psi.types.PyOverridingClassMembersProvider} + * * @author Dennis.Ushakov */ public class PyCustomMember extends UserDataHolderBase { @@ -55,6 +60,8 @@ public class PyCustomMember extends UserDataHolderBase { * Force resolving to {@link MyInstanceElement} even if element is function */ private boolean myAlwaysResolveToCustomElement; + private Icon myIcon = AllIcons.Nodes.Method; + private PyCustomMemberTypeInfo myCustomTypeInfo; public PyCustomMember(@NotNull final String name, @Nullable final String type, final boolean resolveToInstance) { myName = name; @@ -166,7 +173,7 @@ public class PyCustomMember extends UserDataHolderBase { if (myTarget != null) { return myTarget.getIcon(0); } - return AllIcons.Nodes.Method; + return myIcon; } @Nullable @@ -241,6 +248,26 @@ public class PyCustomMember extends UserDataHolderBase { return ((MyInstanceElement)element).getThis().equals(this); } + /** + * @param icon icon to use (will be used method icon otherwise) + */ + public PyCustomMember withIcon(@NotNull final Icon icon) { + myIcon = icon; + return this; + } + + /** + * Adds custom info to type if class has {@link #myTypeName} set. + * Info could be later obtained by key. + * + * @param customInfo custom info to add + */ + public PyCustomMember withCustomTypeInfo(@NotNull final PyCustomMemberTypeInfo customInfo) { + Preconditions.checkState(myTypeName != null, "Cant add custom type info if no type provided"); + myCustomTypeInfo = customInfo; + return this; + } + private class MyInstanceElement extends ASTWrapperPsiElement implements PyTypedElement { private final PyClass myClass; private final PsiElement myContext; @@ -260,7 +287,11 @@ public class PyCustomMember extends UserDataHolderBase { return myTypeCallback.fun(myContext); } else if (myClass != null) { - return PyPsiFacade.getInstance(getProject()).createClassType(myClass, !myResolveToInstance); + final PyClassType type = PyPsiFacade.getInstance(getProject()).createClassType(myClass, !myResolveToInstance); + if (myCustomTypeInfo != null) { + myCustomTypeInfo.fill(type); + } + return type; } return null; } diff --git a/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMemberTypeInfo.java b/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMemberTypeInfo.java new file mode 100644 index 000000000000..5fda8d4d2393 --- /dev/null +++ b/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMemberTypeInfo.java @@ -0,0 +1,55 @@ +/* + * 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. + */ +package com.jetbrains.python.codeInsight; + +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.UserDataHolder; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Info to add to type of custom member. + * + * @author Ilya.Kazakevich + */ +public class PyCustomMemberTypeInfo { + @NotNull + private final Map, K> myCustomInfo = new HashMap, K>(); + + public PyCustomMemberTypeInfo(@NotNull final Key key, @NotNull final K value) { + this(Collections.singleton(Pair.create(key, value))); + } + + public PyCustomMemberTypeInfo(@NotNull final Iterable, K>> customInfo) { + for (final Pair, K> pair : customInfo) { + myCustomInfo.put(pair.first, pair.second); + } + } + + public PyCustomMemberTypeInfo(@NotNull final Map, K> customInfo) { + myCustomInfo.putAll(customInfo); + } + + void fill(@NotNull final UserDataHolder typeToFill) { + for (final Map.Entry, K> entry : myCustomInfo.entrySet()) { + typeToFill.putUserData(entry.getKey(), entry.getValue()); + } + } +} diff --git a/python/psi-api/src/com/jetbrains/python/nameResolver/NameResolverTools.java b/python/psi-api/src/com/jetbrains/python/nameResolver/NameResolverTools.java index 4c1bd04080ab..ea1e3a479662 100644 --- a/python/psi-api/src/com/jetbrains/python/nameResolver/NameResolverTools.java +++ b/python/psi-api/src/com/jetbrains/python/nameResolver/NameResolverTools.java @@ -27,6 +27,7 @@ import com.intellij.psi.util.QualifiedName; import com.intellij.util.Function; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; +import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -108,8 +109,8 @@ public final class NameResolverTools { * Same as {@link #isName(PyElement, FQNamesProvider...)} for call expr, but first checks name. * Aliases not supported, but much lighter that way * - * @param call expr - * @param function names to check + * @param call expr + * @param function names to check * @return true if callee is correct */ public static boolean isCalleeShortCut(@NotNull final PyCallExpression call, @@ -142,7 +143,8 @@ public final class NameResolverTools { /** * Checks if some string contains last component one of name - * @param text test to check + * + * @param text test to check * @param names */ public static boolean isContainsName(@NotNull final String text, @NotNull final FQNamesProvider names) { @@ -153,15 +155,32 @@ public final class NameResolverTools { } return false; } + /** * Checks if some file contains last component one of name - * @param file file to check + * + * @param file file to check * @param names */ public static boolean isContainsName(@NotNull final PsiFile file, @NotNull final FQNamesProvider names) { return isContainsName(file.getText(), names); } + /** + * Check if class has parent with some name + * @param child class to check + */ + public static boolean isSubclass(@NotNull final PyClass child, + @NotNull final FQNamesProvider parentName, + @NotNull final TypeEvalContext context) { + for (final String nameToCheck : parentName.getNames()) { + if (child.isSubclass(nameToCheck, context)) { + return true; + } + } + return false; + } + /** * Looks for call of some function */ diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index c9bf4b266bcd..5f68c45df0bd 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -312,7 +312,7 @@ public class PyTargetExpressionImpl extends PyBaseElementImplemptyMap(), context); } diff --git a/python/src/com/jetbrains/python/psi/types/PyCollectionTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyCollectionTypeImpl.java index 933df88216f9..8e6b315eb866 100644 --- a/python/src/com/jetbrains/python/psi/types/PyCollectionTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyCollectionTypeImpl.java @@ -34,6 +34,16 @@ public class PyCollectionTypeImpl extends PyClassTypeImpl implements PyCollectio myElementTypes = elementTypes; } + + @Nullable + @Override + public PyType getReturnType(@NotNull final TypeEvalContext context) { + if (isDefinition()) { + return new PyCollectionTypeImpl(getPyClass(), false, myElementTypes); + } + return null; + } + @NotNull @Override public List getElementTypes(@NotNull TypeEvalContext context) { @@ -52,6 +62,11 @@ public class PyCollectionTypeImpl extends PyClassTypeImpl implements PyCollectio return new PyCollectionTypeImpl(pyClass, isDefinition, elementTypes); } + @Override + public PyClassType toInstance() { + return myIsDefinition ? new PyCollectionTypeImpl(myClass, false, myElementTypes) : this; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -81,4 +96,4 @@ public class PyCollectionTypeImpl extends PyClassTypeImpl implements PyCollectio } return result; } -} +} \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java index ae436c2f45d2..f9381c9fc09c 100644 --- a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java +++ b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java @@ -17,6 +17,8 @@ package com.jetbrains.python.fixtures; import com.google.common.base.Joiner; import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupEx; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ex.QuickFixWrapper; import com.intellij.execution.actions.ConfigurationContext; @@ -439,5 +441,30 @@ public abstract class PyTestCase extends UsefulTestCase { //noinspection ConstantConditions return getCommonCodeStyleSettings().getIndentOptions(); } + + /** + * When you have more than one completion variant, you may use this method providing variant to choose. + * It only works for one caret (multiple carets not supported) and since it puts tab after completion, be sure to limit + * line somehow (i.e. with comment). + *
+ * Example: "user.n[caret]." There are "name" and "nose" fields. + * By calling this function with "nose" you will end with "user.nose ". + */ + protected final void completeCaretWithMultipleVariants(@NotNull final String... desiredVariants) { + final LookupElement[] lookupElements = myFixture.completeBasic(); + final LookupEx lookup = myFixture.getLookup(); + if (lookupElements != null && lookupElements.length > 1) { + // More than one element returned, check directly because completion can't work in this case + for (final LookupElement element : lookupElements) { + final String suggestedString = element.getLookupString(); + if (Arrays.asList(desiredVariants).contains(suggestedString)) { + myFixture.getLookup().setCurrentItem(element); + lookup.setCurrentItem(element); + myFixture.completeBasicAllCarets('\t'); + return; + } + } + } + } } From 37bccc2af6f55be439c2a43ce2f708c83280c938 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 16 Feb 2016 15:19:00 +0300 Subject: [PATCH 49/84] diff: simplify --- .../diff/comparison/ChunkOptimizer.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/ChunkOptimizer.java b/platform/diff-impl/src/com/intellij/diff/comparison/ChunkOptimizer.java index 6b38549c1e14..b1e97aadbbd5 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/ChunkOptimizer.java +++ b/platform/diff-impl/src/com/intellij/diff/comparison/ChunkOptimizer.java @@ -226,12 +226,12 @@ abstract class ChunkOptimizer { List touchLines = touchSide.select(myData1, myData2); int touchStart = touchSide.select(range2.start1, range2.start2); - int shiftForward = findUnimportantLineShift(touchLines, touchStart, equalForward, true, 0); - int shiftBackward = findUnimportantLineShift(touchLines, touchStart - 1, equalBackward, false, 0); + int shiftForward = findNextUnimportantLine(touchLines, touchStart, equalForward, 0); + int shiftBackward = findPrevUnimportantLine(touchLines, touchStart - 1, equalBackward, 0); if (shiftForward == -1 && shiftBackward == -1 && myThreshold != 0) { - shiftForward = findUnimportantLineShift(touchLines, touchStart, equalForward, true, myThreshold); - shiftBackward = findUnimportantLineShift(touchLines, touchStart - 1, equalBackward, false, myThreshold); + shiftForward = findNextUnimportantLine(touchLines, touchStart, equalForward, myThreshold); + shiftBackward = findPrevUnimportantLine(touchLines, touchStart - 1, equalBackward, myThreshold); } if (shiftForward == 0 || shiftBackward == 0) return 0; @@ -240,12 +240,16 @@ abstract class ChunkOptimizer { return shiftForward != -1 ? shiftForward : -shiftBackward; } - private static int findUnimportantLineShift(@NotNull List lines, int offset, int count, boolean leftToRight, int threshold) { + private static int findNextUnimportantLine(@NotNull List lines, int offset, int count, int threshold) { for (int i = 0; i < count; i++) { - int index = leftToRight ? offset + i : offset - i; - if (lines.get(index).getNonSpaceChars() <= threshold) { - return i; - } + if (lines.get(offset + i).getNonSpaceChars() <= threshold) return i; + } + return -1; + } + + private static int findPrevUnimportantLine(@NotNull List lines, int offset, int count, int threshold) { + for (int i = 0; i < count; i++) { + if (lines.get(offset - i).getNonSpaceChars() <= threshold) return i; } return -1; } From 7384fdf517a00ba0d481e4ac80941dbd25553e61 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 16 Feb 2016 15:43:09 +0300 Subject: [PATCH 50/84] diff: do not optimize chunks, that are already bounded by empty line --- .../com/intellij/diff/comparison/ChunkOptimizer.java | 11 +++++++---- .../diff/comparison/LineComparisonUtilTest.kt | 6 ++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/ChunkOptimizer.java b/platform/diff-impl/src/com/intellij/diff/comparison/ChunkOptimizer.java index b1e97aadbbd5..993b735e39d7 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/ChunkOptimizer.java +++ b/platform/diff-impl/src/com/intellij/diff/comparison/ChunkOptimizer.java @@ -82,6 +82,9 @@ abstract class ChunkOptimizer { int equalForward = expandForward(myData1, myData2, range1.end1, range1.end2, range1.end1 + count2, range1.end2 + count2); int equalBackward = expandBackward(myData1, myData2, range2.start1 - count1, range2.start2 - count1, range2.start1, range2.start2); + // nothing to do + if (equalForward == 0 && equalBackward == 0) return; + // merge chunks left [A]B[B] -> [AB]B if (equalForward == count2) { myRanges.remove(myRanges.size() - 1); @@ -226,12 +229,12 @@ abstract class ChunkOptimizer { List touchLines = touchSide.select(myData1, myData2); int touchStart = touchSide.select(range2.start1, range2.start2); - int shiftForward = findNextUnimportantLine(touchLines, touchStart, equalForward, 0); - int shiftBackward = findPrevUnimportantLine(touchLines, touchStart - 1, equalBackward, 0); + int shiftForward = findNextUnimportantLine(touchLines, touchStart, equalForward + 1, 0); + int shiftBackward = findPrevUnimportantLine(touchLines, touchStart - 1, equalBackward + 1, 0); if (shiftForward == -1 && shiftBackward == -1 && myThreshold != 0) { - shiftForward = findNextUnimportantLine(touchLines, touchStart, equalForward, myThreshold); - shiftBackward = findPrevUnimportantLine(touchLines, touchStart - 1, equalBackward, myThreshold); + shiftForward = findNextUnimportantLine(touchLines, touchStart, equalForward + 1, myThreshold); + shiftBackward = findPrevUnimportantLine(touchLines, touchStart - 1, equalBackward + 1, myThreshold); } if (shiftForward == 0 || shiftBackward == 0) return 0; 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 e97750d310a5..fe4e76b9d7c0 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt @@ -269,6 +269,12 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { testAll() } + lines { + ("A_B_o_o_Y_Z_ _A_B_ _ _Y_Z" - "A_B_o_o_Y_Z_ _A_B_u_u_Y_Z_ _A_B_ _ _Y_Z") + default(ins(9, 9, 7)) + testAll() + } + lines { ("A_B_o_o_ _A_B_z_z" - "A_B_o_o_ _A_B_u_u_ _A_B_z_z") default(ins(5, 5, 5)) From a327fffeec55b9aaeaeffafc02612aa531a48ec8 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 16 Feb 2016 15:47:27 +0300 Subject: [PATCH 51/84] IDEA-151702 diff: optimize chunks by searching for an unimportant line in inserted/deleted fragment --- .../diff/comparison/ChunkOptimizer.java | 65 ++++++++++++++++--- .../diff/comparison/LineComparisonUtilTest.kt | 31 +++++++++ 2 files changed, 87 insertions(+), 9 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/ChunkOptimizer.java b/platform/diff-impl/src/com/intellij/diff/comparison/ChunkOptimizer.java index 993b735e39d7..f762d86637ee 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/ChunkOptimizer.java +++ b/platform/diff-impl/src/com/intellij/diff/comparison/ChunkOptimizer.java @@ -24,6 +24,7 @@ import com.intellij.diff.util.Side; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.registry.Registry; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -226,21 +227,59 @@ abstract class ChunkOptimizer { @Override protected int getShift(@NotNull Side touchSide, int equalForward, int equalBackward, @NotNull Range range1, @NotNull Range range2) { + Integer shift; + + shift = getUnchangedBoundaryShift(touchSide, equalForward, equalBackward, range1, range2, 0); + if (shift != null) return shift; + + shift = getChangedBoundaryShift(touchSide, equalForward, equalBackward, range1, range2, 0); + if (shift != null) return shift; + + shift = getUnchangedBoundaryShift(touchSide, equalForward, equalBackward, range1, range2, myThreshold); + if (shift != null) return shift; + + shift = getChangedBoundaryShift(touchSide, equalForward, equalBackward, range1, range2, myThreshold); + if (shift != null) return shift; + + return 0; + } + + /** + * search for an empty line boundary in unchanged lines + * ie: we want insertion/deletion to go right before/after of an empty line + */ + @Nullable + private Integer getUnchangedBoundaryShift(@NotNull Side touchSide, + int equalForward, int equalBackward, + @NotNull Range range1, @NotNull Range range2, + int threshold) { List touchLines = touchSide.select(myData1, myData2); int touchStart = touchSide.select(range2.start1, range2.start2); - int shiftForward = findNextUnimportantLine(touchLines, touchStart, equalForward + 1, 0); - int shiftBackward = findPrevUnimportantLine(touchLines, touchStart - 1, equalBackward + 1, 0); + int shiftForward = findNextUnimportantLine(touchLines, touchStart, equalForward + 1, threshold); + int shiftBackward = findPrevUnimportantLine(touchLines, touchStart - 1, equalBackward + 1, threshold); - if (shiftForward == -1 && shiftBackward == -1 && myThreshold != 0) { - shiftForward = findNextUnimportantLine(touchLines, touchStart, equalForward + 1, myThreshold); - shiftBackward = findPrevUnimportantLine(touchLines, touchStart - 1, equalBackward + 1, myThreshold); - } + return getShift(shiftForward, shiftBackward); + } - if (shiftForward == 0 || shiftBackward == 0) return 0; - if (shiftForward == -1 && shiftBackward == -1) return 0; + /** + * search for an empty line boundary in changed lines + * ie: we want insertion/deletion to start/end with an empty line + */ + @Nullable + private Integer getChangedBoundaryShift(@NotNull Side touchSide, + int equalForward, int equalBackward, + @NotNull Range range1, @NotNull Range range2, + int threshold) { + Side nonTouchSide = touchSide.other(); + List nonTouchLines = nonTouchSide.select(myData1, myData2); + int changeStart = nonTouchSide.select(range1.end1, range1.end2); + int changeEnd = nonTouchSide.select(range2.start1, range2.start2); - return shiftForward != -1 ? shiftForward : -shiftBackward; + int shiftForward = findNextUnimportantLine(nonTouchLines, changeStart, equalForward + 1, threshold); + int shiftBackward = findPrevUnimportantLine(nonTouchLines, changeEnd - 1, equalBackward + 1, threshold); + + return getShift(shiftForward, shiftBackward); } private static int findNextUnimportantLine(@NotNull List lines, int offset, int count, int threshold) { @@ -256,5 +295,13 @@ abstract class ChunkOptimizer { } return -1; } + + @Nullable + private static Integer getShift(int shiftForward, int shiftBackward) { + if (shiftForward == -1 && shiftBackward == -1) return null; + if (shiftForward == 0 || shiftBackward == 0) return 0; + + return shiftForward != -1 ? shiftForward : -shiftBackward; + } } } 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 fe4e76b9d7c0..843435ff81cf 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt @@ -288,6 +288,37 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { } } + fun `test prefer chunks bounded by short line`() { + lines { + ("A====_B====_o====_o====_Y====_Z====_!_A====_B====_z====_z====_Y====_Z====" - + "A====_B====_o====_o====_Y====_Z====_!_A====_B====_u====_u====_Y====_Z====_!_A====_B====_z====_z====_Y====_Z====") + default(ins(7, 7, 7)) + testAll() + } + + lines { + ("A====_B====_o====_o====_Y====_Z====_ _A====_B====_!_!_Y====_Z====" - + "A====_B====_o====_o====_Y====_Z====_ _A====_B====_u====_u====_Y====_Z====_ _A====_B====_!_!_Y====_Z====") + default(ins(7, 7, 7)) + testAll() + } + + lines { + ("A====_B====_o====_o====_Y====_Z====_!_A====_B====_ _ _Y====_Z====" - + "A====_B====_o====_o====_Y====_Z====_!_A====_B====_u====_u====_Y====_Z====_!_A====_B====_ _ _Y====_Z====") + default(ins(9, 9, 7)) + testAll() + } + } + + fun `test prefer chunks bounded by empty line - using inserted content`() { + lines { + ("e_x_A_B_z" - "x_A_B_ _q_A_B_z") + default(del(0, 0, 1), ins(4, 3, 4)) + testAll() + } + } + fun `test prefer smaller amount of chunks`() { lines() { ("X_A_X_Y_" - "X_Y_") From a73345cc93b8fbe541918a8433de88eefe51de79 Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Wed, 17 Feb 2016 12:37:55 +0300 Subject: [PATCH 52/84] #EDU-544 fixed: open link from StudyToolWindow in default browser --- .../edu/learning/ui/StudyBrowserWindow.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyBrowserWindow.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyBrowserWindow.java index ced05bf7ed30..a4bcce6f0e5a 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyBrowserWindow.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyBrowserWindow.java @@ -217,16 +217,10 @@ class StudyBrowserWindow extends JFrame { myEngine.setJavaScriptEnabled(true); myEngine.getLoadWorker().cancel(); ev.preventDefault(); - - ApplicationManager.getApplication().invokeLater(() -> { - final String href = getLink((Element)ev.getTarget()); - if (href == null) return; - final StudyBrowserWindow studyBrowserWindow = new StudyBrowserWindow(false, true); - studyBrowserWindow.addBackAndOpenButtons(); - studyBrowserWindow.load(href); - studyBrowserWindow.setVisible(true); - }); - + final String href = getLink((Element)ev.getTarget()); + if (href == null) return; + BrowserUtil.browse(href); + } } From 3d2498080a1ab14e7f6e15f8b2621153a2cbaf0b Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 17 Feb 2016 11:10:14 +0100 Subject: [PATCH 53/84] fix test --- .../com/intellij/psi/codeStyle/CommonCodeStyleSettings.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java index d1ffa0cc5a1d..4cb85dc4b76a 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java @@ -916,7 +916,7 @@ public class CommonCodeStyleSettings { public int WRAP_ON_TYPING = WrapOnTyping.DEFAULT.intValue; //-------------------------Indent options------------------------------------------------- - public static class IndentOptions implements Cloneable { + public static class IndentOptions implements Cloneable, JDOMExternalizable { public int INDENT_SIZE = 4; public int CONTINUATION_INDENT_SIZE = 8; public int TAB_SIZE = 4; @@ -931,10 +931,12 @@ public class CommonCodeStyleSettings { private static final Key INDENT_OPTIONS_KEY = Key.create("INDENT_OPTIONS_KEY"); private boolean myInaccurate; + @Override public void readExternal(Element element) throws InvalidDataException { DefaultJDOMExternalizer.readExternal(this, element); } + @Override public void writeExternal(Element element) throws WriteExternalException { DefaultJDOMExternalizer.writeExternal(this, element, field -> { if ("KEEP_INDENTS_ON_EMPTY_LINES".equals(field.getName())) { From 7aad9806e9785fcf20442019862829552d9968e8 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Wed, 17 Feb 2016 13:13:31 +0300 Subject: [PATCH 54/84] NPEs fixed --- .../intellij/codeInspection/ui/InspectionNodeInfo.java | 4 ++-- .../codeInspection/ui/InspectionResultsView.java | 9 +-------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java index c6127c741115..f6afb1cca039 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java @@ -65,8 +65,8 @@ public class InspectionNodeInfo extends JPanel { description.setEditable(false); description.setOpaque(false); description.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE); - SingleInspectionProfilePanel.readHTML(description, SingleInspectionProfilePanel.toHTML(description, toolWrapper.loadDescription(), - true)); + final String toolDescription = toolWrapper.loadDescription(); + SingleInspectionProfilePanel.readHTML(description, SingleInspectionProfilePanel.toHTML(description, toolDescription == null ? "" : toolDescription, true)); add(ScrollPaneFactory.createScrollPane(description, true), new GridBagConstraints(0, 1, 1, 1, 0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 553de2bbf0b1..91eafe4a6777 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -392,15 +392,8 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren final InspectionTreeNode node = (InspectionTreeNode)pathSelected.getLastPathComponent(); if (node instanceof RefElementNode) { final RefElementNode refElementNode = (RefElementNode)node; - final CommonProblemDescriptor problem = refElementNode.getProblem(); final RefEntity refSelected = refElementNode.getElement(); - if (node.isLeaf()) { - LOG.assertTrue(problem != null); - showInRightPanel(refSelected); - } - else { - showInRightPanel(refSelected); - } + showInRightPanel(refSelected); } else if (node instanceof ProblemDescriptionNode) { final ProblemDescriptionNode problemNode = (ProblemDescriptionNode)node; From 29dd2989fe55c9752fe0469d24f4a783d1713070 Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Wed, 17 Feb 2016 13:28:46 +0300 Subject: [PATCH 55/84] Strip trailing spaces API refactoring, part 2 [IDEA-CR-8203] --- .../editor/StripTrailingSpacesFilter.java | 49 +++++++++++++++ .../StripTrailingSpacesFilterFactory.java | 29 +++++++++ .../editor/StripTrailingSpacesLineFilter.java | 53 ----------------- .../openapi/editor/impl/DocumentImpl.java | 31 ++++++---- ...=> PsiBasedStripTrailingSpacesFilter.java} | 59 +++++++++++++------ .../src/META-INF/PlatformExtensionPoints.xml | 2 +- 6 files changed, 142 insertions(+), 81 deletions(-) create mode 100644 platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilter.java create mode 100644 platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilterFactory.java delete mode 100644 platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesLineFilter.java rename platform/core-impl/src/com/intellij/openapi/editor/impl/{PsiBasedStripTrailingSpacesLineFilter.java => PsiBasedStripTrailingSpacesFilter.java} (50%) diff --git a/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilter.java b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilter.java new file mode 100644 index 000000000000..50dc4f412d3a --- /dev/null +++ b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilter.java @@ -0,0 +1,49 @@ +/* + * 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. + */ +package com.intellij.openapi.editor; + +import org.jetbrains.annotations.NotNull; + +/** + * Allows to suppress stripping spaces from some lines or from entire document when the document is being saved and + * "Strip spaces on Save" option is not "None". + */ +public interface StripTrailingSpacesFilter { + + StripTrailingSpacesFilter NOT_ALLOWED = new StripTrailingSpacesFilter() { + @Override + public boolean isStripSpacesAllowedForLine(int line) { + return false; + } + }; + + StripTrailingSpacesFilter POSTPONED = new StripTrailingSpacesFilter() { + @Override + public boolean isStripSpacesAllowedForLine(int line) { + return false; + } + }; + + StripTrailingSpacesFilter ALL_LINES = new StripTrailingSpacesFilter() { + @Override + public boolean isStripSpacesAllowedForLine(int line) { + return true; + } + }; + + boolean isStripSpacesAllowedForLine(int line); + +} diff --git a/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilterFactory.java b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilterFactory.java new file mode 100644 index 000000000000..7d41d9d00f40 --- /dev/null +++ b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilterFactory.java @@ -0,0 +1,29 @@ +/* + * 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. + */ +package com.intellij.openapi.editor; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class StripTrailingSpacesFilterFactory { + public static final ExtensionPointName EXTENSION_POINT + = new ExtensionPointName("com.intellij.stripTrailingSpacesFilterFactory"); + + @NotNull + public abstract StripTrailingSpacesFilter createFilter(@Nullable Project project, @NotNull Document document); +} diff --git a/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesLineFilter.java b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesLineFilter.java deleted file mode 100644 index 958b76c18870..000000000000 --- a/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesLineFilter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - */ -package com.intellij.openapi.editor; - -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -/** - * Allows to suppress stripping spaces from some lines when a document is being saved and "Strip spaces on Save" option is not "None". - */ -public abstract class StripTrailingSpacesLineFilter { - public static final ExtensionPointName LINE_FILTER_EXTENSION_POINT - = new ExtensionPointName("com.intellij.stripTrailingSpacesLineFilter"); - - /** - * Tells if spaces can be stripped from the document. Returns false if trailing spaces should be preserved regardless of - * the editor settings and other filters. - * - * @param project The current project or null if there is no project context. - * @param document The document. - * @return True if it's OK to strip spaces, false otherwise. - */ - public abstract boolean isStripSpacesAllowed(@Nullable Project project, @NotNull Document document); - - /** - * Processes a document and sets bits to 1 (true) for lines which should remain untouched when trailing spaces are removed. - * - * @param project The current project or null if there is no project context. - * @param document The document to process. - * @param disabledLinesBitSet The bit set which can be modified by the apply() method. Each bit index corresponds to a line - * - * @return True if successful, false if can't be applied now, probably later. - */ - public abstract boolean apply(@Nullable Project project, @NotNull Document document, @NotNull BitSet disabledLinesBitSet); - -} diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java index 976eed7817f7..67b008ed17ff 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java @@ -51,10 +51,9 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Arrays; -import java.util.BitSet; import java.util.List; -import static com.intellij.openapi.editor.StripTrailingSpacesLineFilter.LINE_FILTER_EXTENSION_POINT; +import static com.intellij.openapi.editor.StripTrailingSpacesFilterFactory.EXTENSION_POINT; public class DocumentImpl extends UserDataHolderBase implements DocumentEx { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.DocumentImpl"); @@ -199,13 +198,18 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { if (!isStripTrailingSpacesEnabled) { return true; } - StripTrailingSpacesLineFilter[] filters = LINE_FILTER_EXTENSION_POINT.getExtensions(); - for (StripTrailingSpacesLineFilter filter : filters) { - if (!filter.isStripSpacesAllowed(project, this)) return true; - } - BitSet disabledLinesBitSet = new BitSet(getLineCount()); - for (StripTrailingSpacesLineFilter filter : filters) { - if (!filter.apply(project, this, disabledLinesBitSet)) return false; + List filters = new ArrayList(); + for (StripTrailingSpacesFilterFactory filterFactory : EXTENSION_POINT.getExtensions()) { + StripTrailingSpacesFilter filter = filterFactory.createFilter(project, this); + if (filter == StripTrailingSpacesFilter.NOT_ALLOWED) { + return true; + } + else if (filter == StripTrailingSpacesFilter.POSTPONED) { + return false; + } + else { + filters.add(filter); + } } boolean markAsNeedsStrippingLater = false; @@ -230,7 +234,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { lineLoop: for (int line = 0; line < getLineCount(); line++) { LineSet lineSet = getLineSet(); - if (inChangedLinesOnly && !lineSet.isModified(line) || disabledLinesBitSet.get(line)) continue; + if (inChangedLinesOnly && !lineSet.isModified(line) || !canStripSpacesFrom(line, filters)) continue; int whiteSpaceStart = -1; final int lineEnd = lineSet.getLineEnd(line) - lineSet.getSeparatorLength(line); int lineStart = lineSet.getLineStart(line); @@ -288,6 +292,13 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { return markAsNeedsStrippingLater; } + private static boolean canStripSpacesFrom(int line, @NotNull List filters) { + for (StripTrailingSpacesFilter filter : filters) { + if (!filter.isStripSpacesAllowedForLine(line)) return false; + } + return true; + } + @Override public void setReadOnly(boolean isReadOnly) { if (myIsReadOnly != isReadOnly) { diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/PsiBasedStripTrailingSpacesLineFilter.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/PsiBasedStripTrailingSpacesFilter.java similarity index 50% rename from platform/core-impl/src/com/intellij/openapi/editor/impl/PsiBasedStripTrailingSpacesLineFilter.java rename to platform/core-impl/src/com/intellij/openapi/editor/impl/PsiBasedStripTrailingSpacesFilter.java index 39c948078e0f..5f96c07a1567 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/PsiBasedStripTrailingSpacesLineFilter.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/PsiBasedStripTrailingSpacesFilter.java @@ -18,9 +18,11 @@ package com.intellij.openapi.editor.impl; import com.intellij.lang.Language; import com.intellij.lang.LanguageUtil; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.StripTrailingSpacesLineFilter; +import com.intellij.openapi.editor.StripTrailingSpacesFilter; +import com.intellij.openapi.editor.StripTrailingSpacesFilterFactory; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; @@ -29,28 +31,45 @@ import org.jetbrains.annotations.Nullable; import java.util.BitSet; -public abstract class PsiBasedStripTrailingSpacesLineFilter extends StripTrailingSpacesLineFilter { - @Override - public boolean isStripSpacesAllowed(@Nullable Project project, @NotNull Document document) { - return true; +public abstract class PsiBasedStripTrailingSpacesFilter implements StripTrailingSpacesFilter { + private final @NotNull BitSet myDisabledLinesBitSet; + private final @NotNull Document myDocument; + + public abstract static class Factory extends StripTrailingSpacesFilterFactory { + @NotNull + @Override + public final StripTrailingSpacesFilter createFilter(@Nullable Project project, @NotNull Document document) { + Language language = getDocumentLanguage(document); + if (language != null && isApplicableTo(language)) { + PsiFile psiFile = getPsiFile(project, document); + if (psiFile != null) { + PsiBasedStripTrailingSpacesFilter filter = createFilter(document); + filter.process(psiFile); + return filter; + } + return POSTPONED; + } + return ALL_LINES; + } + + @NotNull + protected abstract PsiBasedStripTrailingSpacesFilter createFilter(@NotNull Document document); + + protected abstract boolean isApplicableTo(@NotNull Language language); + } + + protected PsiBasedStripTrailingSpacesFilter(@NotNull Document document) { + myDocument = document; + myDisabledLinesBitSet = new BitSet(document.getLineCount()); } @Override - public final boolean apply(@Nullable Project project, @NotNull Document document, @NotNull BitSet disabledLinesBitSet) { - Language language = getDocumentLanguage(document); - if (language != null && isApplicableTo(language)) { - PsiFile psiFile = getPsiFile(project, document); - if (psiFile != null) { - return apply(document, psiFile, disabledLinesBitSet); - } - return false; - } - return true; + public boolean isStripSpacesAllowedForLine(int line) { + return !myDisabledLinesBitSet.get(line); } - protected abstract boolean isApplicableTo(@NotNull Language language); - protected abstract boolean apply(@NotNull Document document, @NotNull PsiFile psiFile, BitSet disabledLinesBitSet); + protected abstract void process(@NotNull PsiFile psiFile); @Nullable private static Language getDocumentLanguage(@NotNull Document document) { @@ -72,4 +91,10 @@ public abstract class PsiBasedStripTrailingSpacesLineFilter extends StripTrailin } return null; } + + protected final void disableRange(@NotNull TextRange range) { + int startLine = myDocument.getLineNumber(range.getStartOffset()); + int endLine = myDocument.getLineNumber(range.getEndOffset()); + myDisabledLinesBitSet.set(startLine, endLine); + } } diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index 86ec8d4c1e32..60c4c11a28a1 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -262,6 +262,6 @@ - + From c406b2fb6d8603a5abf2784b6c4ef923a6bd515c Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Wed, 17 Feb 2016 13:42:59 +0300 Subject: [PATCH 56/84] Cleanup --- .../com/intellij/openapi/editor/StripTrailingSpacesFilter.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilter.java b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilter.java index 50dc4f412d3a..9b2c25cc0316 100644 --- a/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilter.java +++ b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilter.java @@ -15,8 +15,6 @@ */ package com.intellij.openapi.editor; -import org.jetbrains.annotations.NotNull; - /** * Allows to suppress stripping spaces from some lines or from entire document when the document is being saved and * "Strip spaces on Save" option is not "None". From a35c9c7d29fab1bba366f680e4108475ddc66e91 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Wed, 17 Feb 2016 14:22:04 +0300 Subject: [PATCH 57/84] inspections: set default AnalysisUIOptions.ANALYSIS_IN_BACKGROUND = true --- .../lang-impl/src/com/intellij/analysis/AnalysisUIOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/analysis/AnalysisUIOptions.java b/platform/lang-impl/src/com/intellij/analysis/AnalysisUIOptions.java index 960c78e1befc..2842c67c72ce 100644 --- a/platform/lang-impl/src/com/intellij/analysis/AnalysisUIOptions.java +++ b/platform/lang-impl/src/com/intellij/analysis/AnalysisUIOptions.java @@ -50,7 +50,7 @@ public class AnalysisUIOptions implements PersistentStateComponent Date: Wed, 17 Feb 2016 12:23:52 +0100 Subject: [PATCH 58/84] ensure conflicts are ordered --- .../com/intellij/refactoring/RenameMethodMultiTest.java | 7 +++---- .../com/intellij/refactoring/BaseRefactoringProcessor.java | 4 +++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/refactoring/RenameMethodMultiTest.java b/java/java-tests/testSrc/com/intellij/refactoring/RenameMethodMultiTest.java index 18f0cbe22483..4247b3a8ab44 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/RenameMethodMultiTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/RenameMethodMultiTest.java @@ -19,7 +19,6 @@ import com.intellij.JavaTestUtil; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiDocumentManager; @@ -71,9 +70,9 @@ public class RenameMethodMultiTest extends MultiFileTestCase { doTest("p.B", "void method()", "finalMethod"); } catch (BaseRefactoringProcessor.ConflictsInTestsException e) { - Assert.assertEquals("Renaming method will override final \"method A.finalMethod()\"\n" + - "Method finalMethod() will override \n" + - "a method of the base class p.A", e.getMessage()); + Assert.assertEquals("Method finalMethod() will override \n" + + "a method of the base class p.A\n" + + "Renaming method will override final \"method A.finalMethod()\"", e.getMessage()); return; } fail("Conflicts were not found"); diff --git a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java index a22c14f226cd..7471a1657789 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java @@ -585,7 +585,9 @@ public abstract class BaseRefactoringProcessor implements Runnable { @Override public String getMessage() { - return StringUtil.join(messages, "\n"); + List result = new ArrayList<>(messages); + Collections.sort(result); + return StringUtil.join(result, "\n"); } } From 3debb1a87c847901971358f7441e2552732d3ead Mon Sep 17 00:00:00 2001 From: Konstantin Ulitin Date: Wed, 17 Feb 2016 14:32:16 +0300 Subject: [PATCH 59/84] better names for web worker threads --- .../backend/src/WorkerManager.kt | 2 +- .../backend/src/WorkerManagerBase.kt | 2 +- .../src/org/jetbrains/debugger/WebWorker.kt | 25 +++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 platform/script-debugger/backend/src/org/jetbrains/debugger/WebWorker.kt diff --git a/platform/script-debugger/backend/src/WorkerManager.kt b/platform/script-debugger/backend/src/WorkerManager.kt index 90459bc2e2cf..882dbd963641 100644 --- a/platform/script-debugger/backend/src/WorkerManager.kt +++ b/platform/script-debugger/backend/src/WorkerManager.kt @@ -19,5 +19,5 @@ package org.jetbrains.debugger * @author Konstantin.Ulitin */ interface WorkerManager { - val activeWorkers: Set + val activeWorkers: Map } \ No newline at end of file diff --git a/platform/script-debugger/backend/src/WorkerManagerBase.kt b/platform/script-debugger/backend/src/WorkerManagerBase.kt index bd14aa0143d9..d6cd091707ba 100644 --- a/platform/script-debugger/backend/src/WorkerManagerBase.kt +++ b/platform/script-debugger/backend/src/WorkerManagerBase.kt @@ -21,5 +21,5 @@ import java.util.* * @author Konstantin.Ulitin */ abstract class WorkerManagerBase : WorkerManager { - override val activeWorkers: Set = Collections.emptySet() + override val activeWorkers: Map = Collections.emptyMap() } \ No newline at end of file diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/WebWorker.kt b/platform/script-debugger/backend/src/org/jetbrains/debugger/WebWorker.kt new file mode 100644 index 000000000000..73290b00f9d8 --- /dev/null +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/WebWorker.kt @@ -0,0 +1,25 @@ +/* + * 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. + */ +package org.jetbrains.debugger + + +/** + * @author Konstantin.Ulitin + */ +interface WebWorker { + val id: String + val url: String +} \ No newline at end of file From 05de8796caca3fd9b0730c248fa9074fd59a21ad Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 17 Feb 2016 14:35:38 +0300 Subject: [PATCH 60/84] IDEA-149950 Bad typo in "Declaration access can be weaker" inspection --- .../daemon/impl/analysis/HighlightMethodUtil.java | 9 +++++---- .../visibility/AccessCanBeTightenedInspection.java | 9 ++++++--- java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java | 7 ++++--- .../src/com/intellij/util/VisibilityUtil.java | 9 ++++++--- .../advHighlighting/AccessLevelClash.java | 2 +- .../advHighlighting/StaticOverride.java | 2 +- .../src/com/siyeh/ig/fixes/ChangeModifierFix.java | 4 ++-- .../visibility/AccessCanBeTightenedInspectionTest.java | 6 +++--- 8 files changed, 28 insertions(+), 20 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index bcd2424fb754..0698df0e079e 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -40,6 +40,7 @@ import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.util.*; import com.intellij.refactoring.util.RefactoringChangeUtil; import com.intellij.ui.ColorUtil; +import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.MostlySingularMultiMap; import com.intellij.util.ui.UIUtil; import com.intellij.xml.util.XmlStringUtil; @@ -100,9 +101,9 @@ public class HighlightMethodUtil { int superAccessLevel = PsiUtil.getAccessLevel(superMethod.getModifierList()); if (accessLevel < superAccessLevel) { String description = JavaErrorMessages.message("weaker.privileges", - createClashMethodMessage(method, superMethod, true), - accessModifier, - PsiUtil.getAccessModifier(superAccessLevel)); + createClashMethodMessage(method, superMethod, true), + VisibilityUtil.toPresentableText(accessModifier), + PsiUtil.getAccessModifier(superAccessLevel)); TextRange textRange; if (includeRealPositionInfo) { if (modifierList.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspection.java index 78a0c28c39ef..d89c92bd8b77 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -32,6 +32,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.usageView.UsageInfo; import com.intellij.util.Processor; +import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.ContainerUtil; import com.siyeh.ig.fixes.ChangeModifierFix; import com.siyeh.ig.psiutils.MethodUtils; @@ -185,12 +186,14 @@ class AccessCanBeTightenedInspection extends BaseJavaBatchLocalInspectionTool { log(member.getName() + " unused; ignore"); return; // do not propose private for unused method } + int max = maxLevel.get(); if (max == PsiUtil.ACCESS_LEVEL_PRIVATE && memberClass == null) { max = suggestPackageLocal(member); } - log(member.getName()+": effective level is '" + PsiUtil.getAccessModifier(max) + "'"); + String maxModifier = PsiUtil.getAccessModifier(max); + log(member.getName() + ": effective level is '" + maxModifier + "'"); if (max < currentLevel) { if (max == PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL && member instanceof PsiClass && childMembersAreUsedOutsideMyPackage.contains(member)) { @@ -205,7 +208,7 @@ class AccessCanBeTightenedInspection extends BaseJavaBatchLocalInspectionTool { } }); assert toHighlight != null : member +" ; " + ((PsiNameIdentifierOwner)member).getNameIdentifier() + "; "+ memberModifierList.getText(); - myHolder.registerProblem(toHighlight, "Access can be "+PsiUtil.getAccessModifier(max), new ChangeModifierFix(PsiUtil.getAccessModifier(max))); + myHolder.registerProblem(toHighlight, "Access can be " + VisibilityUtil.toPresentableText(maxModifier), new ChangeModifierFix(maxModifier)); } } diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java index bd702c64f57a..302bfa32f82d 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -353,10 +353,11 @@ public final class PsiUtil extends PsiUtilCore { } @PsiModifier.ModifierConstant - @Nullable + @NotNull public static String getAccessModifier(@AccessLevel int accessLevel) { + assert accessLevel > 0 && accessLevel <= accessModifiers.length : accessLevel; @SuppressWarnings("UnnecessaryLocalVariable") @PsiModifier.ModifierConstant - final String modifier = accessLevel > accessModifiers.length ? null : accessModifiers[accessLevel - 1]; + final String modifier = accessModifiers[accessLevel - 1]; return modifier; } diff --git a/java/java-psi-api/src/com/intellij/util/VisibilityUtil.java b/java/java-psi-api/src/com/intellij/util/VisibilityUtil.java index 04aa459203ec..970c25f08725 100644 --- a/java/java-psi-api/src/com/intellij/util/VisibilityUtil.java +++ b/java/java-psi-api/src/com/intellij/util/VisibilityUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -31,6 +31,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; public class VisibilityUtil { @@ -107,7 +108,8 @@ public class VisibilityUtil { } @Nls - public static String getVisibilityStringToDisplay(PsiMember member) { + @NotNull + public static String getVisibilityStringToDisplay(@NotNull PsiMember member) { if (member.hasModifierProperty(PsiModifier.PUBLIC)) { return toPresentableText(PsiModifier.PUBLIC); } @@ -120,7 +122,8 @@ public class VisibilityUtil { return toPresentableText(PsiModifier.PACKAGE_LOCAL); } - public static String toPresentableText(@PsiModifier.ModifierConstant String modifier) { + @NotNull + public static String toPresentableText(@PsiModifier.ModifierConstant @NotNull String modifier) { return PsiBundle.visibilityPresentation(modifier); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/AccessLevelClash.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/AccessLevelClash.java index 7fa62b8aa01e..95f045d64325 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/AccessLevelClash.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/AccessLevelClash.java @@ -4,7 +4,7 @@ interface i { } public class a implements i { - void ff() {} + void ff() {} } class ai implements i { public int ff() { return 0;} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/StaticOverride.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/StaticOverride.java index be1914e180dc..0e946e6e8e15 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/StaticOverride.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/StaticOverride.java @@ -34,7 +34,7 @@ interface i2 { class weak { void f1() {} } -class a2 extends weak implements i { +class a2 extends weak implements i { } class a3 { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ChangeModifierFix.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ChangeModifierFix.java index 0e114abf03f4..d6a494b60fc8 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ChangeModifierFix.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ChangeModifierFix.java @@ -23,6 +23,7 @@ import com.intellij.psi.PsiModifierList; import com.intellij.psi.PsiModifierListOwner; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.VisibilityUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.InspectionGadgetsFix; import org.jetbrains.annotations.NonNls; @@ -40,8 +41,7 @@ public class ChangeModifierFix extends InspectionGadgetsFix { @Override @NotNull public String getName() { - return InspectionGadgetsBundle.message("change.modifier.quickfix", - modifierText); + return InspectionGadgetsBundle.message("change.modifier.quickfix", VisibilityUtil.toPresentableText(modifierText)); } @NotNull diff --git a/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspectionTest.java index 38e229346c87..5b6e8c0f0670 100644 --- a/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -27,7 +27,7 @@ public class AccessCanBeTightenedInspectionTest extends LightInspectionTestCase "class C {\n" + " final int /*Access can be private*/fd/**/ = 0;\n" + " /*Access can be private*/public/**/ int fd2;\n" + - " /*Access can be packageLocal*/public/**/ int forSubClass;\n" + + " /*Access can be package local*/public/**/ int forSubClass;\n" + " @Override\n" + " public int hashCode() {\n" + " return fd + fd2;\n" + // use field @@ -58,7 +58,7 @@ public class AccessCanBeTightenedInspectionTest extends LightInspectionTestCase "@interface Ann{ String value(); }\n" + "@Ann(value = C.VAL\n)" + "class C {\n" + - " /*Access can be packageLocal*/public/**/ static final String VAL = \"xx\";\n" + + " /*Access can be package local*/public/**/ static final String VAL = \"xx\";\n" + "}"); } From d499f6c81802b16b04d7b6d9c31e039f153ed234 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 17 Feb 2016 14:37:03 +0300 Subject: [PATCH 61/84] IDEA-139759 SOE in Find Usages while processing macro --- .../progress/impl/CoreProgressManager.java | 107 +++++++++--------- .../progress/util/ProgressWrapper.java | 38 +++++-- .../intellij/concurrency/JobLauncherImpl.java | 84 ++++++-------- .../progress/impl/ProgressIndicatorTest.java | 17 ++- 4 files changed, 136 insertions(+), 110 deletions(-) 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 10a4adda1573..707eb4eb9607 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 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -38,9 +38,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import javax.swing.*; -import java.util.Collection; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.Future; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -406,66 +404,69 @@ public class CoreProgressManager extends ProgressManager implements Disposable { } private void registerIndicatorAndRun(@NotNull ProgressIndicator indicator, - @NotNull Thread currentThread, - ProgressIndicator oldIndicator, - @NotNull Runnable process) { - Set underIndicator; - boolean alreadyUnder; - boolean isStandard; + @NotNull Thread currentThread, + ProgressIndicator oldIndicator, + @NotNull Runnable process) { + List> threadsUnderThisIndicator = new ArrayList>(); synchronized (threadsUnderIndicator) { - underIndicator = threadsUnderIndicator.get(indicator); - if (underIndicator == null) { - underIndicator = new SmartHashSet(); - threadsUnderIndicator.put(indicator, underIndicator); - } - alreadyUnder = !underIndicator.add(currentThread); - isStandard = indicator instanceof StandardProgressIndicator; - if (!isStandard) { - nonStandardIndicators.add(indicator); - if (myCheckCancelledFuture == null) { - myCheckCancelledFuture = startBackgroundIndicatorPing(); + for (ProgressIndicator thisIndicator = indicator; thisIndicator != null; thisIndicator = thisIndicator instanceof WrappedProgressIndicator ? ((WrappedProgressIndicator)thisIndicator).getOriginalProgressIndicator() : null) { + Set underIndicator = threadsUnderIndicator.get(thisIndicator); + if (underIndicator == null) { + underIndicator = new SmartHashSet(); + threadsUnderIndicator.put(thisIndicator, underIndicator); } - } + boolean alreadyUnder = !underIndicator.add(currentThread); + threadsUnderThisIndicator.add(alreadyUnder ? null : underIndicator); - if (indicator.isCanceled()) { - threadsUnderCanceledIndicator.add(currentThread); - } - else { - threadsUnderCanceledIndicator.remove(currentThread); - } - thereIsProcessUnderCanceledIndicator = !threadsUnderCanceledIndicator.isEmpty(); - } - - try { - if (indicator instanceof WrappedProgressIndicator) { - ProgressIndicator wrappee = ((WrappedProgressIndicator)indicator).getOriginalProgressIndicator(); - if (wrappee == indicator) throw new IllegalArgumentException(indicator + " wraps itself"); - registerIndicatorAndRun(wrappee, currentThread, oldIndicator, process); - } - else { - process.run(); - } - } - finally { - synchronized (threadsUnderIndicator) { - boolean removed = alreadyUnder || underIndicator.remove(currentThread); - if (removed && underIndicator.isEmpty()) { - threadsUnderIndicator.remove(indicator); - } + boolean isStandard = thisIndicator instanceof StandardProgressIndicator; if (!isStandard) { - nonStandardIndicators.remove(indicator); - if (nonStandardIndicators.isEmpty()) { - myCheckCancelledFuture.cancel(true); - myCheckCancelledFuture = null; + nonStandardIndicators.add(thisIndicator); + if (myCheckCancelledFuture == null) { + myCheckCancelledFuture = startBackgroundIndicatorPing(); } } - // by this time oldIndicator may have been canceled - if (oldIndicator != null && oldIndicator.isCanceled()) { + + if (thisIndicator.isCanceled()) { threadsUnderCanceledIndicator.add(currentThread); } else { threadsUnderCanceledIndicator.remove(currentThread); } + } + + thereIsProcessUnderCanceledIndicator = !threadsUnderCanceledIndicator.isEmpty(); + } + + try { + process.run(); + } + finally { + synchronized (threadsUnderIndicator) { + ProgressIndicator thisIndicator = null; + // order doesn't matter + for (int i = 0; i < threadsUnderThisIndicator.size(); i++) { + thisIndicator = i == 0 ? indicator : ((WrappedProgressIndicator)thisIndicator).getOriginalProgressIndicator(); + Set underIndicator = threadsUnderThisIndicator.get(i); + boolean removed = underIndicator != null && underIndicator.remove(currentThread); + if (removed && underIndicator.isEmpty()) { + threadsUnderIndicator.remove(thisIndicator); + } + boolean isStandard = thisIndicator instanceof StandardProgressIndicator; + if (!isStandard) { + nonStandardIndicators.remove(thisIndicator); + if (nonStandardIndicators.isEmpty()) { + myCheckCancelledFuture.cancel(true); + myCheckCancelledFuture = null; + } + } + // by this time oldIndicator may have been canceled + if (oldIndicator != null && oldIndicator.isCanceled()) { + threadsUnderCanceledIndicator.add(currentThread); + } + else { + threadsUnderCanceledIndicator.remove(currentThread); + } + } thereIsProcessUnderCanceledIndicator = !threadsUnderCanceledIndicator.isEmpty(); } } diff --git a/platform/core-impl/src/com/intellij/openapi/progress/util/ProgressWrapper.java b/platform/core-impl/src/com/intellij/openapi/progress/util/ProgressWrapper.java index 438e936005de..f9a1d6a6226b 100644 --- a/platform/core-impl/src/com/intellij/openapi/progress/util/ProgressWrapper.java +++ b/platform/core-impl/src/com/intellij/openapi/progress/util/ProgressWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -43,12 +43,13 @@ public class ProgressWrapper extends AbstractProgressIndicatorBase implements Wr } protected ProgressWrapper(@NotNull ProgressIndicator original, boolean checkCanceledForMe) { + assert original instanceof StandardProgressIndicator : "Original indicator must be StandardProcessIndicator"; myOriginal = original; myCheckCanceledForMe = checkCanceledForMe; nested = 1 + (original instanceof ProgressWrapper ? ((ProgressWrapper)original).nested : -1); - if (nested > 50) { - LOG.error("Too many wrapped indicators"); - } + //if (nested > 50) { + // LOG.error("Too many wrapped indicators"); + //} ProgressManager.assertNotCircular(original); } @@ -60,13 +61,36 @@ public class ProgressWrapper extends AbstractProgressIndicatorBase implements Wr @Override public final boolean isCanceled() { - return myOriginal.isCanceled() || myCheckCanceledForMe && super.isCanceled(); + ProgressWrapper current = this; + while (true) { + if (current.myCheckCanceledForMe && current.isCanceledRaw()) return true; + ProgressIndicator original = current.getOriginalProgressIndicator(); + if (original instanceof ProgressWrapper) { + current = (ProgressWrapper)original; + } + else { + return original.isCanceled(); + } + } } + private boolean isCanceledRaw() { return super.isCanceled(); } + private void checkCanceledRaw() { super.checkCanceled(); } + @Override public final void checkCanceled() { - myOriginal.checkCanceled(); - super.checkCanceled(); + ProgressWrapper current = this; + while (true) { + current.checkCanceledRaw(); + ProgressIndicator original = current.getOriginalProgressIndicator(); + if (original instanceof ProgressWrapper) { + current = (ProgressWrapper)original; + } + else { + original.checkCanceled(); + break; + } + } } @Override diff --git a/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java b/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java index ddcb275f1391..41a35bc2e87a 100644 --- a/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java +++ b/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -96,7 +96,7 @@ public class JobLauncherImpl extends JobLauncher { Boolean result = processImmediatelyIfTooFew(things, wrapper, runInReadAction, thingProcessor); if (result != null) return result.booleanValue(); - ApplierCompleter applier = new ApplierCompleter(null, runInReadAction, wrapper, things, thingProcessor, 0, things.size(), null); + ApplierCompleter applier = new ApplierCompleter<>(null, runInReadAction, wrapper, things, thingProcessor, 0, things.size(), null); try { pool.invoke(applier); if (applier.throwable != null) throw applier.throwable; @@ -109,10 +109,7 @@ public class JobLauncherImpl extends JobLauncher { // then task2 calls checkCancel() and get here return false; } - catch (RuntimeException e) { - throw e; - } - catch (Error e) { + catch (RuntimeException | Error e) { throw e; } catch (Throwable e) { @@ -125,7 +122,7 @@ public class JobLauncherImpl extends JobLauncher { // if {@code things} are too few to be processed in the real pool, returns TRUE if processed successfully, FALSE if not // returns null if things need to be processed in the real pool private static Boolean processImmediatelyIfTooFew(@NotNull final List things, - final ProgressIndicator progress, + @NotNull final ProgressIndicator progress, boolean runInReadAction, @NotNull final Processor thingProcessor) { // commit can be invoked from within write action @@ -136,24 +133,16 @@ public class JobLauncherImpl extends JobLauncher { if (things.size() <= 1 || JobSchedulerImpl.CORES_COUNT <= CORES_FORK_THRESHOLD) { final AtomicBoolean result = new AtomicBoolean(true); - Runnable runnable = new Runnable() { - @Override - public void run() { - ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() { - @Override - public void run() { - //noinspection ForLoopReplaceableByForEach - for (int i = 0; i < things.size(); i++) { - T thing = things.get(i); - if (!thingProcessor.process(thing)) { - result.set(false); - break; - } - } - } - }, progress); + Runnable runnable = () -> ProgressManager.getInstance().executeProcessUnderProgress(() -> { + //noinspection ForLoopReplaceableByForEach + for (int i = 0; i < things.size(); i++) { + T thing = things.get(i); + if (!thingProcessor.process(thing)) { + result.set(false); + break; + } } - }; + }, progress); if (runInReadAction) { if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(runnable)) return false; } @@ -318,35 +307,32 @@ public class JobLauncherImpl extends JobLauncher { @Override public Boolean call() throws Exception { - ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() { - @Override - public void run() { - try { - while (true) { - progress.checkCanceled(); - T element = failedToProcess.poll(); - if (element == null) element = things.take(); + ProgressManager.getInstance().executeProcessUnderProgress(() -> { + try { + while (true) { + progress.checkCanceled(); + T element = failedToProcess.poll(); + if (element == null) element = things.take(); - if (element == tombStone) { - things.offer(element); - result = true; + if (element == tombStone) { + things.offer(element); + result = true; + break; + } + try { + if (!thingProcessor.process(element)) { + result = false; break; } - try { - if (!thingProcessor.process(element)) { - result = false; - break; - } - } - catch (RuntimeException e) { - failedToProcess.add(element); - throw e; - } + } + catch (RuntimeException e) { + failedToProcess.add(element); + throw e; } } - catch (InterruptedException e) { - throw new RuntimeException(e); - } + } + catch (InterruptedException e) { + throw new RuntimeException(e); } }, progress); return result; @@ -372,7 +358,7 @@ public class JobLauncherImpl extends JobLauncher { } } - List> tasks = new ArrayList>(); + List> tasks = new ArrayList<>(); for (int i = 0; i < JobSchedulerImpl.CORES_COUNT; i++) { tasks.add(pool.submit(new MyTask(i))); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/progress/impl/ProgressIndicatorTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/progress/impl/ProgressIndicatorTest.java index 035ca5d93eb8..2466ab02a621 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/progress/impl/ProgressIndicatorTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/progress/impl/ProgressIndicatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -15,6 +15,8 @@ */ package com.intellij.openapi.progress.impl; +import com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator; +import com.intellij.concurrency.SensitiveProgressWrapper; import com.intellij.ide.util.DelegatingProgressIndicator; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -377,6 +379,19 @@ public class ProgressIndicatorTest extends LightPlatformTestCase { } } + public void testSOEUnderExtremelyNestedWrappedIndicator() { + ProgressIndicator indicator = new DaemonProgressIndicator(); + for (int i=0;i<10000;i++) { + indicator = new SensitiveProgressWrapper(indicator); + } + ProgressManager.getInstance().executeProcessUnderProgress(() -> { + ProgressIndicator progressIndicator = ProgressIndicatorProvider.getGlobalProgressIndicator(); + assertTrue(progressIndicator instanceof SensitiveProgressWrapper); + progressIndicator.checkCanceled(); + progressIndicator.isCanceled(); + }, indicator); + } + public void testBombedIndicator() { final int count = 10; new BombedProgressIndicator(count).runBombed(() -> { From 7bbd6f20d2c758bc4c9059b52ce9b02f7c628a92 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 17 Feb 2016 13:05:23 +0100 Subject: [PATCH 62/84] add type to assertion message --- platform/configuration-store-impl/src/StateMap.kt | 2 +- platform/configuration-store-impl/src/StorageBaseEx.kt | 2 +- platform/configuration-store-impl/src/XmlElementStorage.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/configuration-store-impl/src/StateMap.kt b/platform/configuration-store-impl/src/StateMap.kt index 54e94df82ebb..2941b890e314 100644 --- a/platform/configuration-store-impl/src/StateMap.kt +++ b/platform/configuration-store-impl/src/StateMap.kt @@ -203,7 +203,7 @@ class StateMap private constructor(private val names: Array, private val } val currentState = states.get(index) - LOG.assertTrue(currentState is Element) + LOG.assertTrue(currentState is Element, currentState?.let { it.javaClass.name } ?: "null") states.set(index, if (state == null) null else archiveState(state).toByteArray()) } } diff --git a/platform/configuration-store-impl/src/StorageBaseEx.kt b/platform/configuration-store-impl/src/StorageBaseEx.kt index 72ed7d7cd8a8..bdc7ce320f03 100644 --- a/platform/configuration-store-impl/src/StorageBaseEx.kt +++ b/platform/configuration-store-impl/src/StorageBaseEx.kt @@ -56,7 +56,7 @@ class StateGetter(private val component: PersistentStateCompon try { stateAfterLoad = component.state } - catch(e: Throwable) { + catch (e: Throwable) { LOG.error("Cannot get state after load", e) stateAfterLoad = null } diff --git a/platform/configuration-store-impl/src/XmlElementStorage.kt b/platform/configuration-store-impl/src/XmlElementStorage.kt index ceedbe8741e8..f0b2854718e6 100644 --- a/platform/configuration-store-impl/src/XmlElementStorage.kt +++ b/platform/configuration-store-impl/src/XmlElementStorage.kt @@ -226,7 +226,7 @@ fun save(states: StateMap, rootElementName: String, newLiveStates: Map Date: Wed, 17 Feb 2016 15:10:01 +0300 Subject: [PATCH 63/84] diff: fix test - it's expected result was wrong, but was never checked --- .../com/intellij/diff/comparison/LineComparisonUtilTest.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 843435ff81cf..94861b9073e5 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt @@ -411,9 +411,8 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { lines() { ("====}_==== }_Y_====}" - "====}_Y_====}") default(del(1, 1, 1)) // result after second step correction - ignore(mod(1, 1, 2, 1)) // result looks strange because of 'diff.unimportant.line.char.count' - testDefault() - testTrim() + ignore(ins(1, 1, 1), del(2, 3, 2)) // result looks strange because of 'diff.unimportant.line.char.count' + testAll() } } From 6a43e394a168aa5c847c1307b6307a8a14c1530f Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 17 Feb 2016 14:09:19 +0300 Subject: [PATCH 64/84] diff: simplify by-line tests representation --- .../tests/com/intellij/diff/DiffTestCase.kt | 4 -- .../diff/comparison/ComparisonUtilTestBase.kt | 58 ++++++++++++++++++- .../diff/comparison/LineComparisonUtilTest.kt | 57 +++++++++--------- 3 files changed, 87 insertions(+), 32 deletions(-) diff --git a/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt b/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt index 0a66d8d23c55..8145b2a415a7 100644 --- a/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt +++ b/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt @@ -100,10 +100,6 @@ abstract class DiffTestCase : UsefulTestCase() { fun parseSource(string: CharSequence): String = string.toString().replace('_', '\n') - fun parseMatching(before: String, after: String): Couple { - return Couple.of(parseMatching(before), parseMatching(after)) - } - fun parseMatching(matching: String): BitSet { val set = BitSet() matching.filterNot { it == '.' }.forEachIndexed { i, c -> if (c != ' ') set.set(i) } diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilTestBase.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilTestBase.kt index f135220f20e3..1559310cec45 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilTestBase.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilTestBase.kt @@ -25,9 +25,10 @@ import com.intellij.util.containers.ContainerUtil import java.util.* abstract class ComparisonUtilTestBase : DiffTestCase() { - private fun doLineTest(before: Document, after: Document, expected: List?, policy: ComparisonPolicy) { + private fun doLineTest(before: Document, after: Document, matchings: Couple?, expected: List?, policy: ComparisonPolicy) { val fragments = MANAGER.compareLines(before.charsSequence, after.charsSequence, policy, INDICATOR) checkConsistency(fragments, before, after) + if (matchings != null) checkLineMatching(fragments, matchings) if (expected != null) checkLineChanges(fragments, expected) } @@ -111,6 +112,18 @@ abstract class ComparisonUtilTestBase : DiffTestCase() { assertOrderedEquals(changes, expected) } + private fun checkLineMatching(fragments: List, matchings: Couple) { + val set1 = BitSet() + val set2 = BitSet() + for (fragment in fragments) { + set1.set(fragment.startLine1, fragment.endLine1) + set2.set(fragment.startLine2, fragment.endLine2) + } + + assertEquals(matchings.first, set1) + assertEquals(matchings.second, set2) + } + private fun checkDiffMatching(fragments: List, matchings: Couple) { val set1 = BitSet() val set2 = BitSet() @@ -201,7 +214,7 @@ abstract class ComparisonUtilTestBase : DiffTestCase() { assertTrue(change != null || matchings != null) when (type) { - TestType.LINE -> doLineTest(before!!, after!!, change, policy) + TestType.LINE -> doLineTest(before!!, after!!, matchings, change, policy) TestType.WORD -> doWordTest(before!!, after!!, matchings, change, policy) TestType.CHAR -> doCharTest(before!!, after!!, matchings, change, policy) TestType.SPLITTER -> { @@ -267,6 +280,47 @@ abstract class ComparisonUtilTestBase : DiffTestCase() { fun ignore() { ignoreMatching = parseMatching(before, after) } + + private fun parseMatching(before: String, after: String): Couple { + if (type == TestType.LINE) { + val builder = this@TestBuilder + return Couple.of(parseLineMatching(before, builder.before!!), parseLineMatching(after, builder.after!!)) + } + else { + return Couple.of(parseMatching(before), parseMatching(after)) + } + } + + fun parseLineMatching(matching: String, document: Document): BitSet { + assertEquals(matching.length, document.textLength) + + val lines1 = matching.split('_', '*') + val lines2 = document.charsSequence.split('\n') + assertEquals(lines1.size, lines2.size) + for (i in 0..lines1.size - 1) { + assertEquals(lines1[i].length, lines2[i].length, "line $i") + } + + + val set = BitSet() + + var index = 0 + var lineNumber = 0 + while (index < matching.length) { + var end = matching.indexOfAny(listOf("_", "*"), index) + 1 + if (end == 0) end = matching.length + + val line = matching.subSequence(index, end) + if (line.find { it != ' ' && it != '_' } != null) { + assert(!line.contains(' ')) + set.set(lineNumber) + } + lineNumber++ + index = end + } + + return set + } } 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 94861b9073e5..9144618851d3 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt @@ -257,7 +257,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { fun `test regression - shifted similar lines should be matched as a single change, not insertion-deletion`() { lines { (" X_ X" - " X_ X") - default(mod(0, 0, 2, 2)) + ("--_---" - "---_----").default() testDefault() } } @@ -265,25 +265,25 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { fun `test prefer chunks bounded by empty line`() { lines { ("A_B_o_o_Y_Z_ _A_B_z_z_Y_Z" - "A_B_o_o_Y_Z_ _A_B_u_u_Y_Z_ _A_B_z_z_Y_Z") - default(ins(7, 7, 7)) + (" _ _ _ _ _ _ _ _ _ _ _ _ " - " _ _ _ _ _ _ _-_-_-_-_-_-_-_ _ _ _ _ _ ").default() testAll() } lines { ("A_B_o_o_Y_Z_ _A_B_ _ _Y_Z" - "A_B_o_o_Y_Z_ _A_B_u_u_Y_Z_ _A_B_ _ _Y_Z") - default(ins(9, 9, 7)) + (" _ _ _ _ _ _ _ _ _ _ _ _ " - " _ _ _ _ _ _ _ _ _-_-_-_-_-_-_-_ _ _ _ ").default() testAll() } lines { ("A_B_o_o_ _A_B_z_z" - "A_B_o_o_ _A_B_u_u_ _A_B_z_z") - default(ins(5, 5, 5)) + (" _ _ _ _ _ _ _ _ " - " _ _ _ _ _-_-_-_-_-_ _ _ _ ").default() testAll() } lines { ("o_o_Y_Z_ _z_z_Y_Z" - "o_o_Y_Z_ _u_u_Y_Z_ _z_z_Y_Z") - default(ins(5, 5, 5)) + (" _ _ _ _ _ _ _ _ " - " _ _ _ _ _-_-_-_-_-_ _ _ _ ").default() testAll() } } @@ -292,21 +292,24 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { lines { ("A====_B====_o====_o====_Y====_Z====_!_A====_B====_z====_z====_Y====_Z====" - "A====_B====_o====_o====_Y====_Z====_!_A====_B====_u====_u====_Y====_Z====_!_A====_B====_z====_z====_Y====_Z====") - default(ins(7, 7, 7)) + (" _ _ _ _ _ _ _ _ _ _ _ _ " - + " _ _ _ _ _ _ _-----_-----_-----_-----_-----_-----_-_ _ _ _ _ _ ").default() testAll() } lines { ("A====_B====_o====_o====_Y====_Z====_ _A====_B====_!_!_Y====_Z====" - "A====_B====_o====_o====_Y====_Z====_ _A====_B====_u====_u====_Y====_Z====_ _A====_B====_!_!_Y====_Z====") - default(ins(7, 7, 7)) + (" _ _ _ _ _ _ _ _ _ _ _ _ " - + " _ _ _ _ _ _ _-----_-----_-----_-----_-----_-----_-_ _ _ _ _ _ ").default() testAll() } lines { ("A====_B====_o====_o====_Y====_Z====_!_A====_B====_ _ _Y====_Z====" - "A====_B====_o====_o====_Y====_Z====_!_A====_B====_u====_u====_Y====_Z====_!_A====_B====_ _ _Y====_Z====") - default(ins(9, 9, 7)) + (" _ _ _ _ _ _ _ _ _ _ _ _ " - + " _ _ _ _ _ _ _ _ _-----_-----_-----_-----_-_-----_-----_ _ _ _ ").default() testAll() } } @@ -314,7 +317,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { fun `test prefer chunks bounded by empty line - using inserted content`() { lines { ("e_x_A_B_z" - "x_A_B_ _q_A_B_z") - default(del(0, 0, 1), ins(4, 3, 4)) + ("-_ _ _ _ " - " _ _ _-_-_-_-_ ").default() testAll() } } @@ -322,12 +325,13 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { fun `test prefer smaller amount of chunks`() { lines() { ("X_A_X_Y_" - "X_Y_") - default(del(0, 0, 2)) + ("-_-_ _ _" - " _ _").default() testAll() } lines() { (" __x___y" - "__y") + ("-**-*__ " - "__ ").default() default(del(0, 0, 3)) testAll() } @@ -335,7 +339,8 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { lines { ("U======_X======_Y======_z======_X======_Y======_X======_U======_X======_z======" - "U======_Y======_X======_U======_X======") - default(del(1, 1, 4), del(9, 5, 1)) + (" _-------_-------_-------_-------_ _ _ _ _-------" - + " _ _ _ _ ").default() testAll() } } @@ -343,7 +348,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { fun `test regression - can trim chunks after 'compareTwoSteps'`() { lines { ("q__7_ 6_ 7" - "_7") - default(del(0, 0, 1), del(3, 2, 2)) + ("-*_ _--*--" - "_ ").default() testDefault() } } @@ -351,7 +356,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { fun `test regression - can trim chunks after 'optimizeLineChunks'`() { lines { ("A=====_ B=====_ }_}_B=====_" - "A=====_ }_}_B=====_") - default(del(1, 1, 1)) + (" _-------_ _ _ _" - " _ _ _ _").default() testAll() } } @@ -359,26 +364,26 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { fun `test bad cases caused by 'compareTwoStep' logic`() { lines { ("x_!" - "!_x_y") - default(del(0, 0, 1), ins(2, 1, 2)) + ("-_ " - " _-_-").default() testAll() } lines { ("!_x_y" - "x_!") - default(del(0, 0, 1), mod(2, 1, 1, 1)) + ("-_ _-" - " _-").default() testAll() } lines { ("x_! " - "!_x_y") - default(mod(0, 0, 2, 3)) - trim(del(0, 0, 1), ins(2, 1, 2)) + ("-_--" - "-_-_-").default() + ("-_ " - " _-_-").trim() testAll() } lines { ("!_x_y" - "x_! ") - default(del(0, 0, 1), mod(2, 1, 1, 1)) + ("-_ _-" - " _--").default() testAll() } @@ -393,16 +398,16 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { fun `test bad cases caused by 'compareSmart' logic`() { lines { ("A=====_ B=====_ }_}_B=====" - "A=====_ }_}_B=====") - // TODO trim(del(1, 1, 1)) - default(del(1, 1, 1)) - trim(ins(1, 1, 2), del(2, 4, 3)) + // TODO (" _-------_ _ _ " - " _ _ _ ").trim() + (" _-------_ _ _ " - " _ _ _ ").default() + (" _ _--_-_------" - " _--_-_ ").trim() testAll() } lines { ("A=====_ B=====_X_ }_}_Z_B=====_" - "A=====_ }_}_B=====_") - // TODO default(del(1, 1, 2), del(5, 3, 1)) - default(mod(1, 1, 5, 2)) + // TODO (" _-------_-_ _ _-_ _" - " _ _ _ _").default() + (" _-------_-_--_-_-_ _" - " _--_-_ _").default() testAll() } } @@ -410,8 +415,8 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { fun `test trim changed blocks after second step correction`() { lines() { ("====}_==== }_Y_====}" - "====}_Y_====}") - default(del(1, 1, 1)) // result after second step correction - ignore(ins(1, 1, 1), del(2, 3, 2)) // result looks strange because of 'diff.unimportant.line.char.count' + (" _------_ _ " - " _ _ ").default() // result after second step correction + (" _ _-_-----" - " _-_ ").ignore() // result looks strange because of 'diff.unimportant.line.char.count' testAll() } } @@ -419,7 +424,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { fun `test second step correction processes all confusing lines`() { lines { ("====}_==== }_Y_==== }_====}" - "==== }_Y_==== }") - default(del(0, 0, 1), del(4, 3, 1)) + ("-----_ _ _ _-----" - " _ _ ").default() testDefault() } } From 46fc9db45c8a85ada51d9c50c04f7d7f0313e6d3 Mon Sep 17 00:00:00 2001 From: Denis Fokin Date: Wed, 17 Feb 2016 15:11:01 +0300 Subject: [PATCH 65/84] IDEA-146813 Loosing focus in Recent Files/Recently edited files window --- .../com/intellij/ide/actions/Switcher.java | 124 ++++++++++-------- 1 file changed, 71 insertions(+), 53 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java index 8d2aca5b48ae..32aa407010f9 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java @@ -218,6 +218,59 @@ public class Switcher extends AnAction implements DumbAware { final Alarm myAlarm; final SwitcherSpeedSearch mySpeedSearch; final String myTitle; + + + private class MyFocusTraversalPolicy extends FocusTraversalPolicy { + + @Override + public Component getComponentAfter(Container aContainer, Component aComponent) { + return aComponent == toolWindows ? files : toolWindows; + } + + @Override + public Component getComponentBefore(Container aContainer, Component aComponent) { + return aComponent == toolWindows ? files : toolWindows; + } + + @Override + public Component getFirstComponent(Container aContainer) { + return toolWindows; + } + + @Override + public Component getLastComponent(Container aContainer) { + return files; + } + + @Override + public Component getDefaultComponent(Container aContainer) { + return files; + } + } + + private static void exchangeSelectionState (JBList toClear, JBList toSelect) { + if (toSelect.getModel().getSize() > 0) { + int index = Math.min(toClear.getSelectedIndex(), toSelect.getModel().getSize() - 1); + toSelect.setSelectedIndex(index); + toSelect.ensureIndexIsVisible(index); + toClear.clearSelection(); + } + } + + private class MyToolWindowsListFocusListener extends FocusAdapter { + @Override + public void focusGained(FocusEvent e) { + exchangeSelectionState(files, toolWindows); + } + } + + private class MyFilesListFocusListener extends FocusAdapter { + @Override + public void focusGained(FocusEvent e) { + exchangeSelectionState(toolWindows, files); + } + } + final ClickListener myClickListener = new ClickListener() { @Override public boolean onClick(@NotNull MouseEvent e, int clickCount) { @@ -287,6 +340,7 @@ public class Switcher extends AnAction implements DumbAware { } toolWindows = new JBList(twModel); + toolWindows.addFocusListener(new MyToolWindowsListFocusListener()); if (pinned) { new NameFilteringListModel(toolWindows, new Function() { @NotNull @@ -526,6 +580,7 @@ public class Switcher extends AnAction implements DumbAware { ScrollingUtil.installActions(files); files.addMouseListener(this); files.addMouseMotionListener(this); + files.addFocusListener(new MyFilesListFocusListener()); myClickListener.installOn(files); ScrollingUtil.ensureSelectionExists(files); @@ -569,12 +624,6 @@ public class Switcher extends AnAction implements DumbAware { }).createPopup(); if (isPinnedMode()) { - new AnAction(null, null, null) { - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - changeSelection(); - } - }.registerCustomShortcutSet(CustomShortcutSet.fromString("TAB"), this, myPopup); new AnAction(null, null, null) { @Override public void actionPerformed(@NotNull AnActionEvent e) { @@ -600,6 +649,22 @@ public class Switcher extends AnAction implements DumbAware { } myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, myPopup); myPopup.showInCenterOf(window); + + Container popupFocusAncestor = myPopup.getContent().getFocusCycleRootAncestor(); + + popupFocusAncestor.setFocusTraversalPolicy(new MyFocusTraversalPolicy()); + + addFocusTraversalKeys(popupFocusAncestor, KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, "RIGHT"); + addFocusTraversalKeys(popupFocusAncestor, KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, "LEFT"); + + } + + private static void addFocusTraversalKeys (Container focusCycleRoot, int focusTraversalType, String keyStroke) { + Set focusTraversalKeySet = focusCycleRoot.getFocusTraversalKeys(focusTraversalType); + + Set set = new HashSet(focusTraversalKeySet); + set.add(KeyStroke.getKeyStroke(keyStroke)); + focusCycleRoot.setFocusTraversalKeys(focusTraversalType, set); } @NotNull @@ -653,12 +718,6 @@ public class Switcher extends AnAction implements DumbAware { if (ctrl && isAutoHide() || enter) { navigate(e); } - else if (e.getKeyCode() == VK_LEFT) { - goLeft(); - } - else if (e.getKeyCode() == VK_RIGHT) { - goRight(); - } } KeyEvent lastEvent; @@ -673,18 +732,6 @@ public class Switcher extends AnAction implements DumbAware { closeTabOrToolWindow(); break; } - if (e.getKeyCode() == ALT_KEY) { - changeSelection(); - } - } - - private void changeSelection() { - if (isFilesSelected()) { - goLeft(); - } - else { - goRight(); - } } private void closeTabOrToolWindow() { @@ -721,7 +768,6 @@ public class Switcher extends AnAction implements DumbAware { } }, 300); if (jList.getModel().getSize() == 1) { - goLeft(); removeElementAt(jList, selectedIndex); this.remove(jList); this.remove(separator); @@ -793,38 +839,10 @@ public class Switcher extends AnAction implements DumbAware { return getSelectedList() == toolWindows; } - private void goRight() { - if ((isFilesSelected() || !isFilesVisible()) && isAutoHide()) { - cancel(); - } - else { - if (files.getModel().getSize() > 0) { - final int index = Math.min(toolWindows.getSelectedIndex(), files.getModel().getSize() - 1); - files.setSelectedIndex(index); - files.ensureIndexIsVisible(index); - toolWindows.getSelectionModel().clearSelection(); - IdeFocusManager.findInstanceByComponent(files).requestFocus(files, true); - } - } - } - private void cancel() { myPopup.cancel(); } - private void goLeft() { - if (isToolWindowsSelected() && isAutoHide()) { - cancel(); - } - else { - if (toolWindows.getModel().getSize() > 0) { - toolWindows.setSelectedIndex(Math.min(files.getSelectedIndex(), toolWindows.getModel().getSize() - 1)); - files.getSelectionModel().clearSelection(); - IdeFocusManager.findInstanceByComponent(toolWindows).requestFocus(toolWindows, true); - } - } - } - public void go(boolean forward) { JBList selected = getSelectedList(); JList list = selected; From 3ccd2111c0abe9fe5f80b1ad18ead9aeb63cfb82 Mon Sep 17 00:00:00 2001 From: irengrig Date: Tue, 16 Feb 2016 16:24:41 +0100 Subject: [PATCH 66/84] json schema, do not check if recorded schema files exist (and do not delete mappings for no more existing), rather provide correct validation --- .../jsonSchema/JsonSchemaConfigurable.java | 33 +++++++++---------- .../JsonSchemaMappingsConfigurable.java | 10 +++--- .../jsonSchema/JsonSchemaMappingsView.java | 7 ++-- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/json/src/com/jetbrains/jsonSchema/JsonSchemaConfigurable.java b/json/src/com/jetbrains/jsonSchema/JsonSchemaConfigurable.java index 4c005900c3f0..e1b7daeebe2e 100644 --- a/json/src/com/jetbrains/jsonSchema/JsonSchemaConfigurable.java +++ b/json/src/com/jetbrains/jsonSchema/JsonSchemaConfigurable.java @@ -6,7 +6,6 @@ import com.intellij.openapi.ui.NamedConfigurable; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.CollectConsumer; import com.jetbrains.jsonSchema.impl.JsonSchemaReader; import org.jetbrains.annotations.Nls; @@ -22,18 +21,18 @@ import java.io.IOException; */ public class JsonSchemaConfigurable extends NamedConfigurable { private final Project myProject; - @NotNull private final VirtualFile myFile; + @NotNull private final String mySchemaFilePath; @NotNull private final JsonSchemaMappingsConfigurationBase.SchemaInfo mySchema; @Nullable private final Runnable myTree; private JsonSchemaMappingsView myView; private String myDisplayName; public JsonSchemaConfigurable(Project project, - @NotNull VirtualFile schemaFile, @NotNull JsonSchemaMappingsConfigurationBase.SchemaInfo schema, + @NotNull String schemaFilePath, @NotNull JsonSchemaMappingsConfigurationBase.SchemaInfo schema, @Nullable Runnable updateTree) { super(true, updateTree); myProject = project; - myFile = schemaFile; + mySchemaFilePath = schemaFilePath; mySchema = schema; myTree = updateTree; myDisplayName = mySchema.getName(); @@ -98,27 +97,25 @@ public class JsonSchemaConfigurable extends NamedConfigurable collectConsumer = new CollectConsumer<>(); - final File file = new File(myProject.getBasePath(), myView.getSchemaSubPath()); - try { - if (!JsonSchemaReader.isJsonSchema(FileUtil.loadFile(file), collectConsumer)) { - final String message; - if (collectConsumer.getResult().isEmpty()) message = "Can not read JSON schema from file (Unknown reason)"; - else message = "Can not read JSON schema from file: " + StringUtil.join(collectConsumer.getResult(), "; "); - throw new ConfigurationException(message); - } - } - catch (IOException e) { - throw new ConfigurationException("Can not read JSON schema from file: " + e.getMessage()); + final CollectConsumer collectConsumer = new CollectConsumer<>(); + final File file = new File(myProject.getBasePath(), myView.getSchemaSubPath()); + try { + if (!JsonSchemaReader.isJsonSchema(FileUtil.loadFile(file), collectConsumer)) { + final String message; + if (collectConsumer.getResult().isEmpty()) message = "Can not read JSON schema from file (Unknown reason)"; + else message = "Can not read JSON schema from file: " + StringUtil.join(collectConsumer.getResult(), "; "); + throw new ConfigurationException(message); } } + catch (IOException e) { + throw new ConfigurationException("Can not read JSON schema from file: " + e.getMessage()); + } } @Override public void reset() { if (myView == null) return; - myView.setItems(myFile, mySchema.getPatterns()); + myView.setItems(mySchemaFilePath, mySchema.getPatterns()); setDisplayName(mySchema.getName()); } diff --git a/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsConfigurable.java b/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsConfigurable.java index 06e870840274..0d6058a7d1b7 100644 --- a/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsConfigurable.java +++ b/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsConfigurable.java @@ -194,7 +194,8 @@ public class JsonSchemaMappingsConfigurable extends MasterDetailsComponent imple }*/ private void addCreatedMappings(@NotNull VirtualFile schemaFile, @NotNull final JsonSchemaMappingsConfigurationBase.SchemaInfo info) { - final MyNode node = new MyNode(new JsonSchemaConfigurable(myProject, schemaFile, info, myTreeUpdater), info.isApplicationLevel()); + final MyNode node = new MyNode(new JsonSchemaConfigurable(myProject, FileUtil.toSystemDependentName(schemaFile.getPath()), + info, myTreeUpdater), info.isApplicationLevel()); addNode(node, myRoot); selectNodeInTree(node, true); } @@ -206,11 +207,8 @@ public class JsonSchemaMappingsConfigurable extends MasterDetailsComponent imple final List list = getStoredList(); for (JsonSchemaMappingsConfigurationBase.SchemaInfo info : list) { - final String[] parts = info.getRelativePathToSchema().replace('\\', '/').split("/"); - final VirtualFile schemaFile = VfsUtil.findRelativeFile(myProject.getBaseDir(), parts); - if (schemaFile != null) { - myRoot.add(new MyNode(new JsonSchemaConfigurable(myProject, schemaFile, info, myTreeUpdater), info.isApplicationLevel())); - } + myRoot.add(new MyNode(new JsonSchemaConfigurable(myProject, new File(myProject.getBasePath(), info.getRelativePathToSchema()).getPath(), + info, myTreeUpdater), info.isApplicationLevel())); } ((DefaultTreeModel) myTree.getModel()).reload(myRoot); if (myRoot.children().hasMoreElements()) { diff --git a/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsView.java b/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsView.java index ff753e7a506b..e9e6c1acf48b 100644 --- a/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsView.java +++ b/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsView.java @@ -127,7 +127,7 @@ public class JsonSchemaMappingsView { return items; } - public void setItems(VirtualFile schemaFile, final List data) { + public void setItems(String schemaFilePath, final List data) { /*final ArrayList copy = new ArrayList(); if (myProject != null && myProject.getBasePath() != null) { for (JsonSchemaMappingsConfigurationBase.Item item : copy) { @@ -141,8 +141,9 @@ public class JsonSchemaMappingsView { } else { copy.addAll(data); }*/ - mySchemaField.setText(FileUtil.toSystemDependentName(schemaFile.getPath())); - myTableView.setModelAndUpdateColumns(new ListTableModel(createColumns(), new ArrayList(data))); + mySchemaField.setText(schemaFilePath); + myTableView.setModelAndUpdateColumns( + new ListTableModel(createColumns(), new ArrayList(data))); } public String getSchemaSubPath() { From 1af342b137137febbd564c90e2b0823b28ae5122 Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 17 Feb 2016 12:38:06 +0100 Subject: [PATCH 67/84] WEB-20369 JSON Schema: copy errors found on reading schema into the Event Log --- .../jetbrains/jsonSchema/JsonSchemaConfigurable.java | 10 +++++++++- .../jsonSchema/JsonSchemaMappingsConfigurable.java | 2 ++ .../jetbrains/jsonSchema/impl/JsonSchemaReader.java | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/json/src/com/jetbrains/jsonSchema/JsonSchemaConfigurable.java b/json/src/com/jetbrains/jsonSchema/JsonSchemaConfigurable.java index e1b7daeebe2e..880b6a7abd91 100644 --- a/json/src/com/jetbrains/jsonSchema/JsonSchemaConfigurable.java +++ b/json/src/com/jetbrains/jsonSchema/JsonSchemaConfigurable.java @@ -2,6 +2,7 @@ package com.jetbrains.jsonSchema; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.NamedConfigurable; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.io.FileUtil; @@ -104,14 +105,21 @@ public class JsonSchemaConfigurable extends NamedConfigurable Date: Wed, 17 Feb 2016 12:45:33 +0100 Subject: [PATCH 68/84] WEB-20368 JSON Schema: rename "Add" chooser title to the "Select JSON Schema File" --- json/src/com/intellij/json/JsonBundle.properties | 3 +++ .../jetbrains/jsonSchema/JsonSchemaMappingsConfigurable.java | 4 +++- json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsView.java | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/json/src/com/intellij/json/JsonBundle.properties b/json/src/com/intellij/json/JsonBundle.properties index b73ef1f4fddf..516c91f6ed26 100644 --- a/json/src/com/intellij/json/JsonBundle.properties +++ b/json/src/com/intellij/json/JsonBundle.properties @@ -37,3 +37,6 @@ quickfix.add.double.quotes.desc=Wrap with double quotes surround.with.object.literal.desc=object literal json.template.context.type=JSON + +#json schema +json.schema.add.schema.chooser.title=Select JSON Schema File \ No newline at end of file diff --git a/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsConfigurable.java b/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsConfigurable.java index 6ee9865e6c47..0d023655316f 100644 --- a/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsConfigurable.java +++ b/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsConfigurable.java @@ -1,5 +1,6 @@ package com.jetbrains.jsonSchema; +import com.intellij.json.JsonBundle; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -131,7 +132,8 @@ public class JsonSchemaMappingsConfigurable extends MasterDetailsComponent imple private void addProjectSchema() { final VirtualFile file = - FileChooser.chooseFile(FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor(), myProject, null); + FileChooser.chooseFile(FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor().withTitle( + JsonBundle.message("json.schema.add.schema.chooser.title")), myProject, null); if (file != null) { final String relativePath = VfsUtil.getRelativePath(file, myProject.getBaseDir()); if (relativePath == null) { diff --git a/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsView.java b/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsView.java index e9e6c1acf48b..eb43bee8ea20 100644 --- a/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsView.java +++ b/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsView.java @@ -1,5 +1,6 @@ package com.jetbrains.jsonSchema; +import com.intellij.json.JsonBundle; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonShortcuts; import com.intellij.openapi.application.ModalityState; @@ -81,7 +82,7 @@ public class JsonSchemaMappingsView { final JPanel wrapper = new JPanel(new BorderLayout()); final JPanel wrapper2 = new JPanel(new BorderLayout()); mySchemaField = new TextFieldWithBrowseButton(); - SwingHelper.installFileCompletionAndBrowseDialog(myProject, mySchemaField, "Select JSON Schema File", + SwingHelper.installFileCompletionAndBrowseDialog(myProject, mySchemaField, JsonBundle.message("json.schema.add.schema.chooser.title"), FileChooserDescriptorFactory.createSingleFileDescriptor()); attachNavigateToSchema(); final JBLabel label = new JBLabel("JSON schema file:"); From 4740a88b5821ac356e7bcc9fb9e9f46b49146ea1 Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 17 Feb 2016 13:37:30 +0100 Subject: [PATCH 69/84] WEB-20365 JSON Schema: do not remove schema silently on file move/delete --- ...sonSchemaMappingsProjectConfiguration.java | 53 +++++++++++++++ ...JsonSchemaRefactoringListenerProvider.java | 66 +++++++++++++++++++ .../JsonSchemaSelfProviderFactory.java | 14 +--- .../src/META-INF/JsonPlugin.xml | 1 + 4 files changed, 121 insertions(+), 13 deletions(-) create mode 100644 json/src/com/jetbrains/jsonSchema/JsonSchemaRefactoringListenerProvider.java diff --git a/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsProjectConfiguration.java b/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsProjectConfiguration.java index d132be205846..d9f82ea77ca0 100644 --- a/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsProjectConfiguration.java +++ b/json/src/com/jetbrains/jsonSchema/JsonSchemaMappingsProjectConfiguration.java @@ -2,9 +2,16 @@ package com.jetbrains.jsonSchema; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.xmlb.annotations.Transient; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; +import java.util.HashMap; +import java.util.Map; /** * @author Irina.Chernushina on 2/2/2016. @@ -17,6 +24,8 @@ import java.io.File; ) public class JsonSchemaMappingsProjectConfiguration extends JsonSchemaMappingsConfigurationBase { private Project myProject; + @Transient + private final Map mySchemaFiles = new HashMap<>(); public static JsonSchemaMappingsProjectConfiguration getInstance(@NotNull final Project project) { return ServiceManager.getService(project, JsonSchemaMappingsProjectConfiguration.class); @@ -33,4 +42,48 @@ public class JsonSchemaMappingsProjectConfiguration extends JsonSchemaMappingsCo public File convertToAbsoluteFile(@NotNull String path) { return myProject.getBasePath() == null ? new File(path) : new File(myProject.getBasePath(), path); } + + public boolean isRegisteredSchemaFile(@NotNull VirtualFile file) { + return mySchemaFiles.containsKey(file); + } + + @Override + public void setState(@NotNull Map state) { + super.setState(state); + recalculateSchemaFiles(); + } + + @Override + public void addSchema(@NotNull SchemaInfo info) { + super.addSchema(info); + recalculateSchemaFiles(); + } + + @Override + public void removeSchema(@NotNull SchemaInfo info) { + super.removeSchema(info); + recalculateSchemaFiles(); + } + + @Override + public void loadState(JsonSchemaMappingsConfigurationBase state) { + super.loadState(state); + recalculateSchemaFiles(); + } + + private void recalculateSchemaFiles() { + mySchemaFiles.clear(); + if (myProject == null || myProject.getBaseDir() == null) return; + + for (JsonSchemaMappingsConfigurationBase.SchemaInfo info : myState.values()) { + final String pathToSchema = FileUtil.toSystemIndependentName(info.getRelativePathToSchema()); + final VirtualFile schemaFile = VfsUtil.findRelativeFile(myProject.getBaseDir(), pathToSchema); + if (schemaFile != null) mySchemaFiles.put(schemaFile, info); + } + } + + @Nullable + public SchemaInfo getSchemaBySchemaFile(@NotNull final VirtualFile file) { + return mySchemaFiles.get(file); + } } diff --git a/json/src/com/jetbrains/jsonSchema/JsonSchemaRefactoringListenerProvider.java b/json/src/com/jetbrains/jsonSchema/JsonSchemaRefactoringListenerProvider.java new file mode 100644 index 000000000000..8263e5f28717 --- /dev/null +++ b/json/src/com/jetbrains/jsonSchema/JsonSchemaRefactoringListenerProvider.java @@ -0,0 +1,66 @@ +/* + * 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. + */ +package com.jetbrains.jsonSchema; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiUtilBase; +import com.intellij.refactoring.listeners.RefactoringElementListener; +import com.intellij.refactoring.listeners.RefactoringElementListenerProvider; +import com.intellij.refactoring.listeners.UndoRefactoringElementAdapter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Irina.Chernushina on 2/17/2016. + */ +public class JsonSchemaRefactoringListenerProvider implements RefactoringElementListenerProvider { + @Nullable + @Override + public RefactoringElementListener getListener(PsiElement element) { + if (element == null) { + return null; + } + VirtualFile fileAtElement = PsiUtilBase.asVirtualFile(element); + if (fileAtElement == null) { + return null; + } + Project project = element.getProject(); + final JsonSchemaMappingsProjectConfiguration configuration = JsonSchemaMappingsProjectConfiguration.getInstance(project); + final JsonSchemaMappingsConfigurationBase.SchemaInfo schemaInfo = configuration.getSchemaBySchemaFile(fileAtElement); + if (schemaInfo != null && project.getBaseDir() != null) { + return new UndoRefactoringElementAdapter() { + @Override + protected void refactored(@NotNull PsiElement element, @Nullable String oldQualifiedName) { + VirtualFile newFile = PsiUtilBase.asVirtualFile(element); + if (newFile != null) { + final String relativePath = VfsUtil.getRelativePath(newFile, project.getBaseDir()); + if (relativePath != null) { + configuration.removeSchema(schemaInfo); + final JsonSchemaMappingsConfigurationBase.SchemaInfo newSchema = + new JsonSchemaMappingsConfigurationBase.SchemaInfo(schemaInfo.getName(), relativePath, schemaInfo.isApplicationLevel(), + schemaInfo.getPatterns()); + configuration.addSchema(newSchema); + } + } + } + }; + } + return null; + } +} diff --git a/json/src/com/jetbrains/jsonSchema/extension/JsonSchemaSelfProviderFactory.java b/json/src/com/jetbrains/jsonSchema/extension/JsonSchemaSelfProviderFactory.java index c204eccd3e3f..c33ca8030d0a 100644 --- a/json/src/com/jetbrains/jsonSchema/extension/JsonSchemaSelfProviderFactory.java +++ b/json/src/com/jetbrains/jsonSchema/extension/JsonSchemaSelfProviderFactory.java @@ -18,11 +18,8 @@ package com.jetbrains.jsonSchema.extension; import com.intellij.json.JsonFileType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ResourceUtil; -import com.jetbrains.jsonSchema.JsonSchemaMappingsConfigurationBase; import com.jetbrains.jsonSchema.JsonSchemaMappingsProjectConfiguration; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,7 +28,6 @@ import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.net.URL; -import java.util.Map; /** * @author Irina.Chernushina on 2/16/2016. @@ -46,15 +42,7 @@ public class JsonSchemaSelfProviderFactory implements JsonSchemaProviderFactory @Override public boolean isAvailable(@NotNull VirtualFile file) { if (project == null || !JsonFileType.INSTANCE.equals(file.getFileType())) return false; - final JsonSchemaMappingsProjectConfiguration configuration = JsonSchemaMappingsProjectConfiguration.getInstance(project); - final Map map = configuration.getStateMap(); - for (JsonSchemaMappingsConfigurationBase.SchemaInfo info : map.values()) { - final String pathToSchema = FileUtil.toSystemIndependentName(info.getRelativePathToSchema()); - if (! file.getPath().endsWith(pathToSchema)) continue; - final VirtualFile schemaFile = VfsUtil.findRelativeFile(project.getBaseDir(), pathToSchema); - if (file.equals(schemaFile)) return true; - } - return false; + return JsonSchemaMappingsProjectConfiguration.getInstance(project).isRegisteredSchemaFile(file); } @Nullable diff --git a/platform/platform-resources/src/META-INF/JsonPlugin.xml b/platform/platform-resources/src/META-INF/JsonPlugin.xml index 1ece0fb40d13..e766c91dc76e 100644 --- a/platform/platform-resources/src/META-INF/JsonPlugin.xml +++ b/platform/platform-resources/src/META-INF/JsonPlugin.xml @@ -70,6 +70,7 @@ +
From c3f4a14163c1891627c22a26003feba048a3a8d2 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Wed, 17 Feb 2016 15:42:51 +0300 Subject: [PATCH 70/84] [vcs-log] remove cleanupOldNaming --- .../src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java index bb3f4dcbcd36..2a492a24c3cb 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java @@ -80,7 +80,6 @@ public class VcsLogHashMapImpl implements Disposable, VcsLogHashMap { private final PersistentEnumerator myPersistentEnumerator; public VcsLogHashMapImpl(@NotNull final Project project, @NotNull Map logProviders) throws IOException { - cleanupOldNaming(project, logProviders); String logId = calcLogId(project, logProviders); final File mapFile = new File(LOG_CACHE_APP_DIR, logId + "." + VERSION); if (!mapFile.exists()) { @@ -102,13 +101,6 @@ public class VcsLogHashMapImpl implements Disposable, VcsLogHashMap { return project.getLocationHash() + "." + Integer.toHexString(hashcode); } - // TODO remove in IDEA 15 - private static void cleanupOldNaming(@NotNull Project project, @NotNull Map providers) { - int hashcode = calcLogProvidersHash(providers); - String oldLogId = project.getName() + "." + hashcode; - FileUtil.delete(new File(LOG_CACHE, oldLogId)); - } - private static int calcLogProvidersHash(@NotNull final Map logProviders) { List sortedRoots = ContainerUtil.sorted(logProviders.keySet(), new Comparator() { @Override From 8df375f7a83bb2123607cd40748606e18baba123 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Wed, 17 Feb 2016 15:45:48 +0300 Subject: [PATCH 71/84] [vcs-log] register disposer after creating pe --- .../impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java index 2a492a24c3cb..0fcd31b3a46e 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java @@ -86,13 +86,13 @@ public class VcsLogHashMapImpl implements Disposable, VcsLogHashMap { IOUtil.deleteAllFilesStartingWith(new File(LOG_CACHE_APP_DIR, logId)); } - Disposer.register(project, this); myPersistentEnumerator = IOUtil.openCleanOrResetBroken(new ThrowableComputable, IOException>() { @Override public PersistentEnumerator compute() throws IOException { return new PersistentEnumerator(mapFile, new MyCommitIdKeyDescriptor(project), Page.PAGE_SIZE); } }, mapFile); + Disposer.register(project, this); } @NotNull From 1eec8479788704ae9e2fd4e4afe9cb5ef075a3ee Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Wed, 17 Feb 2016 15:56:08 +0300 Subject: [PATCH 72/84] [vcs-log] add NotNull annotation, reformat code --- .../src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java index 0fcd31b3a46e..1a5b50f26bdc 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMapImpl.java @@ -24,7 +24,6 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.ThrowableComputable; -import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.CommonProcessors; @@ -34,7 +33,10 @@ import com.intellij.util.io.IOUtil; import com.intellij.util.io.KeyDescriptor; import com.intellij.util.io.Page; import com.intellij.util.io.PersistentEnumerator; -import com.intellij.vcs.log.*; +import com.intellij.vcs.log.CommitId; +import com.intellij.vcs.log.Hash; +import com.intellij.vcs.log.VcsLogHashMap; +import com.intellij.vcs.log.VcsLogProvider; import com.intellij.vcs.log.impl.HashImpl; import com.intellij.vcs.log.impl.VcsRootsRegistry; import org.jetbrains.annotations.NotNull; @@ -188,7 +190,7 @@ public class VcsLogHashMapImpl implements Disposable, VcsLogHashMap { } private static class MyCommitIdKeyDescriptor implements KeyDescriptor { - private final VcsRootsRegistry myRootsRegistry; + @NotNull private final VcsRootsRegistry myRootsRegistry; public MyCommitIdKeyDescriptor(@NotNull Project project) { myRootsRegistry = ServiceManager.getService(project, VcsRootsRegistry.class); From 380cb9ce8b698f3a06d2c7b2d35b02e5df211d25 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Wed, 17 Feb 2016 14:07:22 +0100 Subject: [PATCH 73/84] 1. ignore generated sources when sending 'unprocessed_sources' event 2. for java modules build target always exclude annotation processors src outputs from source roots --- .../jps/incremental/ModuleBuildTarget.java | 17 +++++++++++++++-- .../jps/incremental/fs/BuildFSState.java | 7 +++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleBuildTarget.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleBuildTarget.java index 05c185862399..8d3cd7931ebb 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleBuildTarget.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleBuildTarget.java @@ -18,6 +18,7 @@ package org.jetbrains.jps.incremental; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.Consumer; import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -135,6 +136,7 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget excludedRootProviders = JpsServiceManager.getInstance().getExtensions(ExcludedJavaSourceRootProvider.class); final Set moduleExcludes = new THashSet(FileUtil.FILE_HASHING_STRATEGY); moduleExcludes.addAll(index.getModuleExcludes(myModule)); + final JpsJavaCompilerConfiguration compilerConfig = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(myModule.getProject()); roots_loop: for (JpsTypedModuleSourceRoot sourceRoot : myModule.getSourceRoots(type)) { @@ -147,8 +149,19 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget excludes = computeRootExcludes(sourceRoot.getFile(), index); + final ProcessorConfigProfile profile = compilerConfig.getAnnotationProcessingProfile(myModule); + if (profile.isEnabled()) { + final File outputDir = ProjectPaths.getAnnotationProcessorGeneratedSourcesOutputDir(myModule, JavaSourceRootType.TEST_SOURCE == sourceRoot.getRootType(), profile); + if (outputDir != null && FileUtil.isAncestor(sourceRoot.getFile(), outputDir, true)) { + excludes = ContainerUtil.newTroveSet(FileUtil.FILE_HASHING_STRATEGY, excludes); + excludes.add(outputDir); + } + } + + roots.add(new JavaSourceRootDescriptor(sourceRoot.getFile(), this, false, false, packagePrefix, excludes)); } return roots; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/fs/BuildFSState.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/fs/BuildFSState.java index b7caa0b575f7..7cd3b4685c4a 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/fs/BuildFSState.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/fs/BuildFSState.java @@ -138,11 +138,18 @@ public class BuildFSState { return false; } final CompileScope scope = context.getScope(); + final BuildRootIndex rootIndex = context.getProjectDescriptor().getBuildRootIndex(); try { delta.lockData(); for (Set files : delta.getSourcesToRecompile().values()) { + files_loop: for (File file : files) { if ((getEventRegistrationStamp(file) > targetBuildStart || FileSystemUtil.lastModified(file) > targetBuildStart) && scope.isAffected(target, file)) { + for (BuildRootDescriptor rd : rootIndex.findAllParentDescriptors(file, context)) { + if (rd.isGenerated()) { // do not send notification for generated sources + continue files_loop; + } + } return true; } } From 260f48f692fa2cc60679bfad4063102d39eaa7af Mon Sep 17 00:00:00 2001 From: "Maxim.Kolmakov" Date: Wed, 17 Feb 2016 14:13:59 +0100 Subject: [PATCH 74/84] All PhpStorm plugins --- platform/platform-resources/src/checkedPlugins.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/platform/platform-resources/src/checkedPlugins.txt b/platform/platform-resources/src/checkedPlugins.txt index 3ea9ed760205..b133a211a5c6 100644 --- a/platform/platform-resources/src/checkedPlugins.txt +++ b/platform/platform-resources/src/checkedPlugins.txt @@ -27,4 +27,15 @@ SourceSafe TFS ro.redeul.google.go com.intellij.plugins.html.instantEditing -com.jetbrains.intellij.api.watcher \ No newline at end of file +com.jetbrains.intellij.api.watcher +com.jetbrains.php.framework +com.intellij.phing +com.intellij.apacheConfig +com.jetbrains.plugins.ini4idea +com.jetbrains.php.gae +com.jetbrains.php.drupal +com.jetbrains.php.wordPress +org.jetbrains.plugins.phpstorm-remote-interpreter +com.jetbrains.php.behat +com.jetbrains.php.blade +com.jetbrains.performancePlugin \ No newline at end of file From 398eca609f3bf458e1b175e5de712c46cf672996 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Wed, 17 Feb 2016 16:22:24 +0300 Subject: [PATCH 75/84] IDEA-151753 Scroll bar doesn't work in 'Pull Members Up/Down' refactoring dialogs call setComponentZOrder after layoutComponent to prevent missing some addNotify calls --- .../com/intellij/ui/components/JBScrollPane.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java index 50238a183fb5..8b8f5e43a4a2 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java @@ -570,7 +570,6 @@ public class JBScrollPane extends JScrollPane { // so that if we don't ask after resetting the bounds we may have gotten the wrong answer. if (viewport != null) { viewport.setBounds(bounds); - pane.setComponentZOrder(viewport, pane.getComponentCount() - 1); if (scrollable != null && hsbOpaque && vsbOpaque) { viewTracksViewportWidth = scrollable.getScrollableTracksViewportWidth(); viewTracksViewportHeight = scrollable.getScrollableTracksViewportHeight(); @@ -655,7 +654,6 @@ public class JBScrollPane extends JScrollPane { int overlapY = !hsbOnTop ? 0 : overlapHeight; vsb.setBounds(vsbBounds.x, vsbBounds.y + overlapY, vsbBounds.width, vsbBounds.height - overlapHeight); vsb.putClientProperty(Alignment.class, vsbOnLeft ? Alignment.LEFT : Alignment.RIGHT); - pane.setComponentZOrder(vsb, 0); } // Modify the bounds of the translucent scroll bar. if (!vsbOpaque) { @@ -714,6 +712,20 @@ public class JBScrollPane extends JScrollPane { vsbOnLeft ? rowHeadBounds.width : vsbBounds.width, hsbOnTop ? hsbBounds.height : colHeadBounds.height); } + if (!vsbOpaque && vsbNeeded || !hsbOpaque && hsbNeeded) { + fixComponentZOrder(vsb, 0); + fixComponentZOrder(viewport, -1); + } + } + + private static void fixComponentZOrder(Component component, int index) { + if (component != null) { + Container parent = component.getParent(); + synchronized (parent.getTreeLock()) { + if (index < 0) index += parent.getComponentCount(); + parent.setComponentZOrder(component, index); + } + } } private void adjustForVSB(Rectangle bounds, Insets insets, Rectangle vsbBounds, boolean vsbOpaque, boolean vsbOnLeft) { From c1cb82f2611201c2b7eeb882f5a2da0e0555836e Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Wed, 17 Feb 2016 16:15:39 +0300 Subject: [PATCH 76/84] Add hyperlink listener to StudySwingToolWindow --- .../src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java index 294eeff042be..56ca088e282a 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java @@ -16,6 +16,7 @@ package com.jetbrains.edu.learning.ui; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.ui.BrowserHyperlinkListener; import com.intellij.ui.ColorUtil; import com.intellij.util.ui.UIUtil; @@ -53,6 +54,7 @@ public class StudySwingToolWindow extends StudyToolWindow { } myTaskTextPane.setBorder(new EmptyBorder(15, 20, 0, 100)); myTaskTextPane.setText(taskText); + myTaskTextPane.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE); return myTaskTextPane; } From 569a7ca9f462659ebcb63f08fde2d70db4576402 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Wed, 17 Feb 2016 16:31:47 +0300 Subject: [PATCH 77/84] Fix calculating type of pyClass constructor call --- .../com/jetbrains/python/psi/types/PyClassTypeImpl.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index 368c9ee05bf9..4e42df6e4a60 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -368,15 +368,12 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @Nullable @Override public PyType getReturnType(@NotNull TypeEvalContext context) { - if (isDefinition()) { - return new PyClassTypeImpl(getPyClass(), false); - } - return null; + return getCallType(context, null); } @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyCallSiteExpression callSite) { if (!isDefinition()) { final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); final List resolveResults = resolveMember(PyNames.CALL, callSite, AccessDirection.READ, resolveContext); @@ -392,6 +389,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { return PyUnionType.union(result); } + } else { + return new PyClassTypeImpl(getPyClass(), false); } return null; From 17743c0a87214465ac3906a69076bed9f6d31a6a Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 17 Feb 2016 14:16:27 +0100 Subject: [PATCH 78/84] unchecked warning: mark as unchecked if passed to strict subtyping (IDEA-151302) --- .../StrictSubtypingConstraint.java | 3 ++- .../genericsHighlighting8/IDEA56754.java | 2 +- ...UncheckedWarningDuringStrictSubtyping.java | 21 +++++++++++++++++++ ...tsWhenParentMethodIsDuringCalculation.java | 5 ++++- .../GraphInferenceHighlightingTest.java | 4 ++++ 5 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedWarningDuringStrictSubtyping.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java index 9177da7586f5..6a5d70ae6475 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java @@ -150,7 +150,8 @@ public class StrictSubtypingConstraint implements ConstraintFormula { final PsiType tSubstituted = tSubstitutor.substitute(parameter); final PsiType sSubstituted = sSubstitutor.substituteWithBoundsPromotion(parameter); if (tSubstituted == null ^ sSubstituted == null) { - return false; + session.setErased(); + return true; } constraints.add(new SubtypingConstraint(tSubstituted, sSubstituted)); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA56754.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA56754.java index 34c407f3dfde..ee489aab75ad 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA56754.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA56754.java @@ -1,5 +1,5 @@ class Foo { public T bar(Class type, String str) { - return Enum.valueOf(type, str); + return Enum.valueOf(type, str); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedWarningDuringStrictSubtyping.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedWarningDuringStrictSubtyping.java new file mode 100644 index 000000000000..fc79f089ce38 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedWarningDuringStrictSubtyping.java @@ -0,0 +1,21 @@ +import java.util.List; + +interface FacetId {} + +abstract class One { + public abstract , C extends One> void findFacetType(FacetId typeId); + private void addSubFacet(FacetId underlyingType) { + findFacetType(underlyingType); + } +} + +class Bar {} +class Foo {} +class Main { + void foo(Bar a) { + m(a); + } + + , C> void m(Bar a) { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IncludeConstraintsWhenParentMethodIsDuringCalculation.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IncludeConstraintsWhenParentMethodIsDuringCalculation.java index 7d5c0557acf7..8869943add57 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IncludeConstraintsWhenParentMethodIsDuringCalculation.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IncludeConstraintsWhenParentMethodIsDuringCalculation.java @@ -12,7 +12,10 @@ class Test { SuperFoo ls = foo(() -> new Foo<>()); +upper bounds: Object, Number +inference variable X has incompatible bounds: + equality constraints: R +upper bounds: Number">() -> new Foo<>()); SuperFoo li = foo(() -> new Foo<>()); SuperFoo lw = foo(() -> new Foo<>()); } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java index e71ad2e341ee..5282649d9f06 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java @@ -383,6 +383,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase doTest(); } + public void testUncheckedWarningDuringStrictSubtyping() throws Exception { + doTest(); + } + private void doTest() throws Exception { doTest(false); } From 42d50e32fe1ac32fad6ef3cf3b4e40dd074c2b7e Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 17 Feb 2016 14:24:07 +0100 Subject: [PATCH 79/84] testdata for IDEA-150688 --- .../lambda/graphInference/IDEA150688.java | 11 +++++++++++ .../daemon/lambda/GraphInferenceHighlightingTest.java | 4 ++++ 2 files changed, 15 insertions(+) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA150688.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA150688.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA150688.java new file mode 100644 index 000000000000..258b71b33649 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA150688.java @@ -0,0 +1,11 @@ +abstract class Issue { + private void enumUsage(Class enumClass) { + passEnumClass(enumClass); + } + + abstract > void passEnumClass(Class var1); + + void a(Enum enumValue) { + Enum constant = Enum.valueOf(enumValue.getClass(), "name"); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java index 5282649d9f06..fb33f7c9af73 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java @@ -387,6 +387,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase doTest(); } + public void testIDEA150688() throws Exception { + doTest(); + } + private void doTest() throws Exception { doTest(false); } From 6caae835c9488132e1d1190b7748647a8d33bf3f Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 17 Feb 2016 12:34:47 +0100 Subject: [PATCH 80/84] IDEA-91793 (Method call in loop condition shall know java iteration structs) --- ...thodCallInLoopConditionInspectionBase.java | 30 +++++++++-- .../MethodCallInLoopConditionInspection.java | 22 -------- .../MethodCallInLoopCondition.java | 52 +++++++++++++++++++ ...thodCallInLoopConditionInspectionTest.java | 36 +++++++++++++ 4 files changed, 114 insertions(+), 26 deletions(-) delete mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/j2me/MethodCallInLoopConditionInspection.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/j2me/method_call_in_loop_condition/MethodCallInLoopCondition.java create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/j2me/MethodCallInLoopConditionInspectionTest.java diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/MethodCallInLoopConditionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/MethodCallInLoopConditionInspectionBase.java index cfd662295820..6a0062f0cd6f 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/MethodCallInLoopConditionInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/MethodCallInLoopConditionInspectionBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -15,13 +15,21 @@ */ package com.siyeh.ig.j2me; +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.psi.*; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.MethodCallUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; public class MethodCallInLoopConditionInspectionBase extends BaseInspection { + + public boolean ignoreIterationMethods = true; + @Override @NotNull public String getDisplayName() { @@ -39,12 +47,18 @@ public class MethodCallInLoopConditionInspectionBase extends BaseInspection { return true; } + @Nullable + @Override + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore iteration method calls", this, "ignoreIterationMethods"); + } + @Override public BaseInspectionVisitor buildVisitor() { return new MethodCallInLoopConditionVisitor(); } - private static class MethodCallInLoopConditionVisitor extends BaseInspectionVisitor { + private class MethodCallInLoopConditionVisitor extends BaseInspectionVisitor { @Override public void visitForStatement(@NotNull PsiForStatement statement) { @@ -80,9 +94,17 @@ public class MethodCallInLoopConditionInspectionBase extends BaseInspection { final PsiElementVisitor visitor = new JavaRecursiveElementWalkingVisitor() { @Override - public void visitMethodCallExpression( - @NotNull PsiMethodCallExpression expression) { + public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) { super.visitMethodCallExpression(expression); + if (ignoreIterationMethods) { + final PsiMethod method = expression.resolveMethod(); + if (MethodCallUtils.isCallToMethod(expression, CommonClassNames.JAVA_UTIL_ITERATOR, PsiType.BOOLEAN, "hasNext") || + MethodCallUtils.isCallToMethod(expression, "java.util.ListIterator", PsiType.BOOLEAN, "hasPrevious") || + MethodCallUtils.isCallToMethod(expression, "java.sql.ResultSet", PsiType.BOOLEAN, "next") || + MethodCallUtils.isCallToMethod(expression, "java.util.Enumeration", PsiType.BOOLEAN, "hasMoreElements")) { + return; + } + } registerMethodCallError(expression); } }; diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/j2me/MethodCallInLoopConditionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/j2me/MethodCallInLoopConditionInspection.java deleted file mode 100644 index 46ddf66f9933..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/j2me/MethodCallInLoopConditionInspection.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.siyeh.igtest.j2me; - -public class MethodCallInLoopConditionInspection { - public void foo() { - for (int i = 0; i < bar(); i++) { - - } - while (bar() != 4) { - foo(); - } - - do { - foo(); - } - while (bar() != 4); - - } - - private int bar() { - return 3; - } -} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/j2me/method_call_in_loop_condition/MethodCallInLoopCondition.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/j2me/method_call_in_loop_condition/MethodCallInLoopCondition.java new file mode 100644 index 000000000000..c8a2cba02a09 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/j2me/method_call_in_loop_condition/MethodCallInLoopCondition.java @@ -0,0 +1,52 @@ +package com.siyeh.igtest.j2me; + +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Enumeration; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class MethodCallInLoopCondition { + public void foo() { + for (int i = 0; i < bar(); i++) { + + } + while (bar() != 4) { + foo(); + } + + do { + foo(); + } + while (bar() != 4); + + } + + private int bar() { + return 3; + } + + void a(Iterator it) { + while (it.hasNext()) { + String s = it.next(); + } + } + + void b(ListIterator it) { + while (it.hasPrevious()) { + String s = it.previous(); + } + } + + void c(Enumeration e) { + while (e.hasMoreElements()) { + e.nextElement(); + } + } + + void d (ResultSet rs) throws SQLException { + while (rs.next()) { + rs.getInt(1); + } + } +} diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/j2me/MethodCallInLoopConditionInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/j2me/MethodCallInLoopConditionInspectionTest.java new file mode 100644 index 000000000000..3fd3b83d36af --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/j2me/MethodCallInLoopConditionInspectionTest.java @@ -0,0 +1,36 @@ +/* + * 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. + */ +package com.siyeh.ig.j2me; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class MethodCallInLoopConditionInspectionTest extends LightInspectionTestCase { + + public void testMethodCallInLoopCondition() { + doTest(); + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new MethodCallInLoopConditionInspection(); + } +} \ No newline at end of file From 02913b8908c6d39ff33c0addfeb230e3cf637635 Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Wed, 17 Feb 2016 17:02:24 +0300 Subject: [PATCH 81/84] Django forms and formset fix: PyCollectionTypeImpl fix return type to support myElementsTypes --- .../jetbrains/python/psi/types/PyCollectionTypeImpl.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/src/com/jetbrains/python/psi/types/PyCollectionTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyCollectionTypeImpl.java index 8e6b315eb866..e89d85dab256 100644 --- a/python/src/com/jetbrains/python/psi/types/PyCollectionTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyCollectionTypeImpl.java @@ -16,6 +16,7 @@ package com.jetbrains.python.psi.types; import com.intellij.psi.PsiElement; +import com.jetbrains.python.psi.PyCallSiteExpression; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyPsiFacade; import org.jetbrains.annotations.NotNull; @@ -44,6 +45,12 @@ public class PyCollectionTypeImpl extends PyClassTypeImpl implements PyCollectio return null; } + @Nullable + @Override + public PyType getCallType(@NotNull final TypeEvalContext context, @Nullable final PyCallSiteExpression callSite) { + return getReturnType(context); + } + @NotNull @Override public List getElementTypes(@NotNull TypeEvalContext context) { From 62ef7e46a8998076a43748a89157a8095599a017 Mon Sep 17 00:00:00 2001 From: nik Date: Wed, 17 Feb 2016 17:33:02 +0300 Subject: [PATCH 82/84] build number baseline set to 146 --- build.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.txt b/build.txt index 96ff88c46f66..6f540e14d3a6 100644 --- a/build.txt +++ b/build.txt @@ -1 +1 @@ -144.SNAPSHOT +146.SNAPSHOT From 31157b069003d1f10467e1c092d8f8352fdfe111 Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Wed, 17 Feb 2016 17:50:26 +0300 Subject: [PATCH 83/84] Strip trailing filters API documentation --- .../editor/StripTrailingSpacesFilter.java | 22 ++++++++++++++++--- .../StripTrailingSpacesFilterFactory.java | 13 +++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilter.java b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilter.java index 9b2c25cc0316..44e2e0282a0b 100644 --- a/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilter.java +++ b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilter.java @@ -18,23 +18,35 @@ package com.intellij.openapi.editor; /** * Allows to suppress stripping spaces from some lines or from entire document when the document is being saved and * "Strip spaces on Save" option is not "None". + * + * @see StripTrailingSpacesFilterFactory */ public interface StripTrailingSpacesFilter { - + + /** + * The filter which completely prohibits removing trailing spaces from a document regardless of other filters. + */ StripTrailingSpacesFilter NOT_ALLOWED = new StripTrailingSpacesFilter() { @Override public boolean isStripSpacesAllowedForLine(int line) { return false; } }; - + + /** + * Tells that strip trailing spaces is not currently possible since some conditions are not met for proper document processing. + * The filter will force another attempt to strip trailing spaces later regardless of other filters. + */ StripTrailingSpacesFilter POSTPONED = new StripTrailingSpacesFilter() { @Override public boolean isStripSpacesAllowedForLine(int line) { return false; } }; - + + /** + * The filter which does not put any restrictions on trailing spaces removal. Other filters may be taken into account. + */ StripTrailingSpacesFilter ALL_LINES = new StripTrailingSpacesFilter() { @Override public boolean isStripSpacesAllowedForLine(int line) { @@ -42,6 +54,10 @@ public interface StripTrailingSpacesFilter { } }; + /** + * @param line The document line. + * @return True if trailing spaces can be removed from the line, false otherwise. + */ boolean isStripSpacesAllowedForLine(int line); } diff --git a/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilterFactory.java b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilterFactory.java index 7d41d9d00f40..02226941ca95 100644 --- a/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilterFactory.java +++ b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesFilterFactory.java @@ -20,10 +20,23 @@ import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** + * An extension point to create filters which may put restrictions on how trailing spaces will be handled in a document. + */ public abstract class StripTrailingSpacesFilterFactory { public static final ExtensionPointName EXTENSION_POINT = new ExtensionPointName("com.intellij.stripTrailingSpacesFilterFactory"); + /** + * Creates a filter which may restrict trailing spaces removal. + * + * @param project The current project or null if there is no project context. + * @param document The document to be processed. + * @return The filter as defined in {@link StripTrailingSpacesFilter}. The factory may return one of the several predefined filters: + * {@link StripTrailingSpacesFilter#NOT_ALLOWED}, {@link StripTrailingSpacesFilter#POSTPONED} or + * {@link StripTrailingSpacesFilter#ALL_LINES}. The latter can be returned, for example, if a language-specific logic is not + * applicable to the document. + */ @NotNull public abstract StripTrailingSpacesFilter createFilter(@Nullable Project project, @NotNull Document document); } From 786455756229bd389695f491cb72c8bf51321219 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 17 Feb 2016 15:52:21 +0100 Subject: [PATCH 84/84] don't log ProcessCanceledException in GotoActionBase (EA-74045 - PCE: AbstractProgressIndicatorBase.checkCanceled) --- .../src/com/intellij/ide/actions/GotoActionBase.java | 4 ++++ 1 file changed, 4 insertions(+) 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 bdbd798ca787..ecce07af15e0 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java @@ -25,6 +25,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; @@ -67,6 +68,9 @@ public abstract class GotoActionBase extends AnAction { myHistoryIndex = strings == null || strings.size() <= 1 || !ourLastStrings.containsKey(myInAction) ? 0 : 1; gotoActionPerformed(e); } + catch (ProcessCanceledException e1) { + myInAction = null; + } catch (Throwable t) { LOG.error(t); myInAction = null;