diff --git a/.idea/modules.xml b/.idea/modules.xml index 8baef1d3adc6..a20d716756d7 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -26,7 +26,6 @@ - diff --git a/build/asm/4_textifier_transient_method.patch b/build/asm/4_textifier_transient_method.patch deleted file mode 100644 index f02b3d8c92e2..000000000000 --- a/build/asm/4_textifier_transient_method.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: org/objectweb/asm/util/Textifier.java -=================================================================== ---- org/objectweb/asm/util/Textifier.java -+++ org/objectweb/asm/util/Textifier.java -@@ -425,7 +425,7 @@ - } - - buf.append(tab); -- appendAccess(access & ~Opcodes.ACC_VOLATILE); -+ appendAccess(access & ~(Opcodes.ACC_VOLATILE|Opcodes.ACC_TRANSIENT)); //[JB: IDEA-166121] - if ((access & Opcodes.ACC_NATIVE) != 0) { - buf.append("native "); - } diff --git a/build/asm/repackage.xml b/build/asm/repackage.xml index 0abbb9199442..b2ffa0cf52e4 100644 --- a/build/asm/repackage.xml +++ b/build/asm/repackage.xml @@ -15,7 +15,7 @@ --> - + @@ -42,7 +42,6 @@ - diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/PackagingElementPath.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/PackagingElementPath.java index 689a5a088249..28b55b12e55c 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/PackagingElementPath.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/PackagingElementPath.java @@ -15,7 +15,6 @@ */ package com.intellij.packaging.impl.artifacts; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.packaging.artifacts.Artifact; import com.intellij.packaging.elements.*; import com.intellij.packaging.impl.elements.ArtifactPackagingElement; @@ -25,6 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.stream.Collectors; /** * @author nik @@ -60,7 +60,8 @@ public class PackagingElementPath { @NotNull public String getPathStringFrom(String separator, @Nullable CompositePackagingElement ancestor) { final List> parents = getParentsFrom(ancestor); - return StringUtil.join(ContainerUtil.reverse(parents), RenameablePackagingElement::getName, separator); + // StringUtil.join ignores empty strings whereas this monstrosity doesn't + return ContainerUtil.reverse(parents).stream().map(RenameablePackagingElement::getName).collect(Collectors.joining("/")); } public List> getParents() { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java index d2af8760cf9f..a92fc8f3add7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java @@ -157,14 +157,12 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV XValuePresentation presentation = new JavaValuePresentation( value, myValueDescriptor.getIdLabel(), exception != null ? exception.getMessage() : null, myValueDescriptor); - if (myValueDescriptor.getLastRenderer() instanceof FullValueEvaluatorProvider) { - XFullValueEvaluator evaluator = ((FullValueEvaluatorProvider)myValueDescriptor.getLastRenderer()) - .getFullValueEvaluator(myEvaluationContext, myValueDescriptor); - if (evaluator != null) { - node.setFullValueEvaluator(evaluator); - } + Renderer lastRenderer = myValueDescriptor.getLastRenderer(); + boolean fullEvaluatorSet = setFullValueEvaluator(lastRenderer); + if (!fullEvaluatorSet && lastRenderer instanceof CompoundNodeRenderer) { + fullEvaluatorSet = setFullValueEvaluator(((CompoundNodeRenderer)lastRenderer).getLabelRenderer()); } - else if (value.length() > XValueNode.MAX_VALUE_LENGTH) { + if (!fullEvaluatorSet && value.length() > XValueNode.MAX_VALUE_LENGTH) { node.setFullValueEvaluator(new JavaFullValueEvaluator(myEvaluationContext) { @Override public void evaluate(@NotNull final XFullValueEvaluationCallback callback) { @@ -180,6 +178,17 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV } node.setPresentation(nodeIcon, presentation, myValueDescriptor.isExpandable()); } + + private boolean setFullValueEvaluator(Renderer renderer) { + if (renderer instanceof FullValueEvaluatorProvider) { + XFullValueEvaluator evaluator = ((FullValueEvaluatorProvider)renderer).getFullValueEvaluator(myEvaluationContext, myValueDescriptor); + if (evaluator != null) { + node.setFullValueEvaluator(evaluator); + return true; + } + } + return false; + } }); } }); @@ -302,13 +311,20 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV String value = truncateToMaxLength(myValue); Renderer lastRenderer = myValueDescriptor.getLastRenderer(); + if (lastRenderer instanceof OnDemandRenderer) { + OnDemandRenderer onDemandRenderer = (OnDemandRenderer)lastRenderer; + if (OnDemandRenderer.isCalculated(myValueDescriptor)) { + lastRenderer = onDemandRenderer.getRenderer(); + } + else { + return; + } + } + if (lastRenderer instanceof CompoundTypeRenderer) { lastRenderer = ((CompoundTypeRenderer)lastRenderer).getLabelRenderer(); } if (lastRenderer instanceof ToStringRenderer) { - if (lastRenderer instanceof LazyToStringRenderer && !((LazyToStringRenderer)lastRenderer).isCalculated(myValueDescriptor)) { - return; - } value = StringUtil.wrapWithDoubleQuote(value); } renderer.renderValue(value); diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java index f8b7afa03a57..d36f8718ef09 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,6 +59,7 @@ class CompoundRendererConfigurable extends JPanel { private final JRadioButton myRbDefaultLabel; private final JRadioButton myRbExpressionLabel; private final JBCheckBox myShowTypeCheckBox; + private final JBCheckBox myOnDemandCheckBox; private final JRadioButton myRbDefaultChildrenRenderer; private final JRadioButton myRbExpressionChildrenRenderer; private final JRadioButton myRbListChildrenRenderer; @@ -88,6 +89,7 @@ class CompoundRendererConfigurable extends JPanel { labelButtonsGroup.add(myRbExpressionLabel); myShowTypeCheckBox = new JBCheckBox(DebuggerBundle.message("label.compound.renderer.configurable.show.type")); + myOnDemandCheckBox = new JBCheckBox(DebuggerBundle.message("label.compound.renderer.configurable.ondemand")); myRbDefaultChildrenRenderer = new JRadioButton(DebuggerBundle.message("label.compound.renderer.configurable.use.default.renderer")); myRbExpressionChildrenRenderer = new JRadioButton(DebuggerBundle.message("label.compound.renderer.configurable.use.expression")); @@ -156,6 +158,8 @@ class CompoundRendererConfigurable extends JPanel { JBUI.insetsLeft(10), 0, 0)); panel.add(myLabelEditor.getComponent(), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, JBUI.insetsLeft(30), 0, 0)); + panel.add(myOnDemandCheckBox, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, + GridBagConstraints.HORIZONTAL, JBUI.insetsLeft(30), 0, 0)); panel.add(new JLabel(DebuggerBundle.message("label.compound.renderer.configurable.when.expanding")), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, @@ -218,7 +222,9 @@ class CompoundRendererConfigurable extends JPanel { } private void updateEnabledState() { - myLabelEditor.setEnabled(myRbExpressionLabel.isSelected()); + boolean isLabelRenderer = myRbExpressionLabel.isSelected(); + myLabelEditor.setEnabled(isLabelRenderer); + myOnDemandCheckBox.setEnabled(isLabelRenderer); final boolean isChildrenExpression = myRbExpressionChildrenRenderer.isSelected(); myChildrenExpandedEditor.setEnabled(isChildrenExpression); @@ -321,6 +327,7 @@ class CompoundRendererConfigurable extends JPanel { if (myRbExpressionLabel.isSelected()) { labelRenderer = new LabelRenderer(); labelRenderer.setLabelExpression(TextWithImportsImpl.fromXExpression(myLabelEditor.getExpression())); + labelRenderer.setOnDemand(myOnDemandCheckBox.isSelected()); } renderer.setLabelRenderer(labelRenderer); // children @@ -362,7 +369,9 @@ class CompoundRendererConfigurable extends JPanel { } else { myRbExpressionLabel.setSelected(true); - myLabelEditor.setExpression(TextWithImportsImpl.toXExpression(((LabelRenderer)labelRenderer).getLabelExpression())); + LabelRenderer lr = (LabelRenderer)labelRenderer; + myLabelEditor.setExpression(TextWithImportsImpl.toXExpression(lr.getLabelExpression())); + myOnDemandCheckBox.setSelected(lr.isOnDemand()); } getTableModel().clear(); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java index c05eff6c8fe2..3182f211bbb6 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.ui.tree.NodeDescriptor; import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; +import com.intellij.debugger.ui.tree.render.OnDemandRenderer; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; import com.intellij.util.containers.HashMap; @@ -115,6 +116,11 @@ public abstract class NodeDescriptorImpl implements NodeDescriptor { myIsSelected = that.myIsSelected; myIsVisible = that.myIsVisible; myUserData = that.myUserData != null ? new HashMap<>(that.myUserData) : null; + + // TODO introduce unified way to handle this + if (myUserData != null) { + myUserData.remove(OnDemandRenderer.ON_DEMAND_CALCULATED); // calculated flag should not be inherited + } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java index 6ac237b51544..a900f2206ca3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java @@ -33,6 +33,7 @@ import com.intellij.debugger.ui.tree.render.*; import com.intellij.debugger.ui.tree.render.Renderer; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; @@ -327,6 +328,16 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException { return null; } + + @Override + public NodeRenderer getRenderer(DebugProcessImpl debugProcess) { + return ValueDescriptorImpl.this.getRenderer(debugProcess); + } + + @Override + public T getUserData(Key key) { + return ValueDescriptorImpl.this.getUserData(key); + } }; descriptor.myFullValue = true; return descriptor; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java index 176803a04837..665d2dfbfdea 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,25 +18,25 @@ package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.DebugProcess; import com.intellij.debugger.engine.DebuggerUtils; -import com.intellij.debugger.engine.evaluation.EvaluateException; -import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; -import com.intellij.debugger.engine.evaluation.EvaluationContext; -import com.intellij.debugger.engine.evaluation.TextWithImports; +import com.intellij.debugger.engine.FullValueEvaluatorProvider; +import com.intellij.debugger.engine.evaluation.*; import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator; +import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.xdebugger.frame.XFullValueEvaluator; import com.sun.jdi.Value; import org.jdom.Element; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; import javax.swing.*; -public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer{ +public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer, FullValueEvaluatorProvider { public static final @NonNls String UNIQUE_ID = "LabelRenderer"; - private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.watch.render.ClassLabelRenderer"); + public boolean myOnDemand; private CachedEvaluator myLabelExpression = createCachedEvaluator(); @@ -62,6 +62,10 @@ public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer{ public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener labelListener) throws EvaluateException { + if (myOnDemand && !OnDemandRenderer.isCalculated(descriptor)) { + return ""; + } + final Value value = descriptor.getValue(); String result; @@ -88,6 +92,15 @@ public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer{ return result; } + @Nullable + @Override + public XFullValueEvaluator getFullValueEvaluator(EvaluationContextImpl evaluationContext, ValueDescriptorImpl valueDescriptor) { + if (myOnDemand && !OnDemandRenderer.isCalculated(valueDescriptor)) { + return OnDemandRenderer.createFullValueEvaluator("… " + getLabelExpression().getText()); + } + return null; + } + public void readExternal(Element element) throws InvalidDataException { super.readExternal(element); DefaultJDOMExternalizer.readExternal(this, element); @@ -111,4 +124,11 @@ public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer{ myLabelExpression.setReferenceExpression(expression); } + public boolean isOnDemand() { + return myOnDemand; + } + + public void setOnDemand(boolean value) { + myOnDemand = value; + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LazyToStringRenderer.kt b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/OnDemandRenderer.kt similarity index 51% rename from java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LazyToStringRenderer.kt rename to java/debugger/impl/src/com/intellij/debugger/ui/tree/render/OnDemandRenderer.kt index 588146149a9b..41fcf05e600f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LazyToStringRenderer.kt +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/OnDemandRenderer.kt @@ -16,63 +16,105 @@ package com.intellij.debugger.ui.tree.render import com.intellij.debugger.DebuggerBundle +import com.intellij.debugger.DebuggerContext import com.intellij.debugger.engine.FullValueEvaluatorProvider +import com.intellij.debugger.engine.JavaValue import com.intellij.debugger.engine.evaluation.EvaluateException import com.intellij.debugger.engine.evaluation.EvaluationContext import com.intellij.debugger.engine.evaluation.EvaluationContextImpl import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl +import com.intellij.debugger.ui.tree.DebuggerTreeNode +import com.intellij.debugger.ui.tree.NodeDescriptor import com.intellij.debugger.ui.tree.ValueDescriptor import com.intellij.openapi.util.Key +import com.intellij.psi.PsiElement import com.intellij.xdebugger.frame.XFullValueEvaluator import com.intellij.xdebugger.frame.XValuePlace import com.intellij.xdebugger.impl.ui.tree.nodes.HeadlessValueEvaluationCallback +import com.sun.jdi.Type +import com.sun.jdi.Value +import javax.swing.Icon /** * @author egor */ -class LazyToStringRenderer : ToStringRenderer(), FullValueEvaluatorProvider { +class OnDemandRenderer(val renderer: NodeRendererImpl) : NodeRendererImpl(), FullValueEvaluatorProvider { init { isEnabled = true } - override fun getFullValueEvaluator(evaluationContext: EvaluationContextImpl?, valueDescriptor: ValueDescriptorImpl): XFullValueEvaluator? { - if (!isCalculated(valueDescriptor)) { - return object : XFullValueEvaluator(DebuggerBundle.message("message.node.toString")) { - override fun startEvaluation(callback: XFullValueEvaluator.XFullValueEvaluationCallback) { - if (callback is HeadlessValueEvaluationCallback) { - val node = callback.node - node.clearFullValueEvaluator() - valueDescriptor.putUserData(LAZY_CALCULATED, true) - node.valueContainer.computePresentation(node, XValuePlace.TREE) - } - callback.evaluated("") - } - }.setShowValuePopup(false) - } - return null - } - @Throws(EvaluateException::class) override fun calcLabel(descriptor: ValueDescriptor, evaluationContext: EvaluationContext, listener: DescriptorLabelListener): String? { if (!isCalculated(descriptor)) { return "" } - return super.calcLabel(descriptor, evaluationContext, listener) + return renderer.calcLabel(descriptor, evaluationContext, listener) } - fun isCalculated(descriptor: ValueDescriptor): Boolean { - return java.lang.Boolean.TRUE == descriptor.getUserData(LAZY_CALCULATED) + override fun getFullValueEvaluator(evaluationContext: EvaluationContextImpl?, valueDescriptor: ValueDescriptorImpl): XFullValueEvaluator? { + if (!isCalculated(valueDescriptor)) { + return createFullValueEvaluator(DebuggerBundle.message("message.node.toString")) + } + return null + } + + override fun buildChildren(value: Value?, builder: ChildrenBuilder?, evaluationContext: EvaluationContext?) { + renderer.buildChildren(value, builder, evaluationContext) + } + + override fun getChildValueExpression(node: DebuggerTreeNode?, context: DebuggerContext?): PsiElement { + return renderer.getChildValueExpression(node, context) + } + + override fun isExpandable(value: Value?, evaluationContext: EvaluationContext?, parentDescriptor: NodeDescriptor?): Boolean { + return renderer.isExpandable(value, evaluationContext, parentDescriptor) + } + + override fun calcValueIcon(descriptor: ValueDescriptor?, + evaluationContext: EvaluationContext?, + listener: DescriptorLabelListener?): Icon? { + return renderer.calcValueIcon(descriptor, evaluationContext, listener) + } + + override fun isApplicable(type: Type?): Boolean { + return renderer.isApplicable(type) } override fun getName(): String { - return "Lazy" + super.getName() + return "OnDemand" + renderer.getName() } override fun getUniqueId(): String { - return "Lazy" + super.getUniqueId() + return "OnDemand" + renderer.getUniqueId() } companion object { - private val LAZY_CALCULATED = Key.create("LAZY_CALCULATED") + @JvmStatic + fun createFullValueEvaluator(text: String): XFullValueEvaluator { + return object : XFullValueEvaluator(text) { + override fun startEvaluation(callback: XFullValueEvaluator.XFullValueEvaluationCallback) { + if (callback is HeadlessValueEvaluationCallback) { + val node = callback.node + node.clearFullValueEvaluator() + setCalculated((node.valueContainer as JavaValue).descriptor) + node.valueContainer.computePresentation(node, XValuePlace.TREE) + } + callback.evaluated("") + } + }.setShowValuePopup(false) + } + + @JvmField + val ON_DEMAND_CALCULATED = Key.create("ON_DEMAND_CALCULATED") + + @JvmStatic + fun isCalculated(descriptor: ValueDescriptor): Boolean { + return ON_DEMAND_CALCULATED.get(descriptor, false) + } + + @JvmStatic + fun setCalculated(descriptor: ValueDescriptor) { + ON_DEMAND_CALCULATED.set(descriptor, true) + } } -} +} \ No newline at end of file diff --git a/java/debugger/openapi/src/com/intellij/debugger/ui/tree/NodeDescriptor.java b/java/debugger/openapi/src/com/intellij/debugger/ui/tree/NodeDescriptor.java index 4ed6de6d6f9e..9dadd8082e69 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/ui/tree/NodeDescriptor.java +++ b/java/debugger/openapi/src/com/intellij/debugger/ui/tree/NodeDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,16 +15,13 @@ */ package com.intellij.debugger.ui.tree; -import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.UserDataHolder; -public interface NodeDescriptor { +public interface NodeDescriptor extends UserDataHolder { String getName(); String getLabel(); - T getUserData(Key key); - void putUserData(Key key, T value); - void displayAs(NodeDescriptor descriptor); void setAncestor(NodeDescriptor oldDescriptor); diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaModule.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaModule.java index bd072f85f38d..5c5ffd7a1371 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaModule.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaModule.java @@ -35,9 +35,15 @@ public interface RefJavaModule extends RefElement { @NotNull Map> getExportedPackageNames(); + @NotNull + Set getServiceInterfaces(); + @NotNull Set getServiceImplementations(); + @NotNull + Set getUsedServices(); + @NotNull List getRequiredModules(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java index dff4e5d182a8..88c679bfa509 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java @@ -19,7 +19,6 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.intention.AddAnnotationPsiFix; import com.intellij.openapi.command.undo.UndoUtil; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; @@ -37,7 +36,6 @@ import java.util.List; * @author cdr */ public class AnnotateMethodFix implements LocalQuickFix { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.AnnotateMethodFix"); protected final String myAnnotation; private final String[] myAnnotationsToRemove; @@ -68,7 +66,8 @@ public class AnnotateMethodFix implements LocalQuickFix { List superMethodSignatures = method.findSuperMethodSignaturesIncludingStatic(true); for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) { PsiMethod superMethod = superMethodSignature.getMethod(); - if (!AnnotationUtil.isAnnotated(superMethod, myAnnotation, false, false) && superMethod.getManager().isInProject(superMethod)) { + if (!AnnotationUtil.isAnnotated(superMethod, myAnnotation, false, false, true) && + superMethod.getManager().isInProject(superMethod)) { int ret = shouldAnnotateBaseMethod(method, superMethod, project); if (ret != 0 && ret != 1) return; if (ret == 0) { @@ -79,7 +78,9 @@ public class AnnotateMethodFix implements LocalQuickFix { if (annotateOverriddenMethods()) { PsiMethod[] methods = OverridingMethodsSearch.search(method).toArray(PsiMethod.EMPTY_ARRAY); for (PsiMethod psiMethod : methods) { - if (AnnotationUtil.isAnnotatingApplicable(psiMethod, myAnnotation) && !AnnotationUtil.isAnnotated(psiMethod, myAnnotation, false, false) && psiMethod.getManager().isInProject(psiMethod)) { + if (AnnotationUtil.isAnnotatingApplicable(psiMethod, myAnnotation) && + !AnnotationUtil.isAnnotated(psiMethod, myAnnotation, false, false, true) && + psiMethod.getManager().isInProject(psiMethod)) { toAnnotate.add(psiMethod); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/java19modules/Java9ModuleEntryPoint.java b/java/java-analysis-impl/src/com/intellij/codeInspection/java19modules/Java9ModuleEntryPoint.java index 63be397acfaa..3329d6334d5f 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/java19modules/Java9ModuleEntryPoint.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/java19modules/Java9ModuleEntryPoint.java @@ -16,8 +16,8 @@ package com.intellij.codeInspection.java19modules; import com.intellij.codeInsight.daemon.impl.analysis.JavaModuleGraphUtil; -import com.intellij.codeInspection.reference.EntryPoint; -import com.intellij.codeInspection.reference.RefElement; +import com.intellij.codeInspection.reference.*; +import com.intellij.codeInspection.visibility.EntryPointWithVisibilityLevel; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.pom.java.LanguageLevel; @@ -30,16 +30,20 @@ import com.intellij.util.xmlb.XmlSerializer; import gnu.trove.THashSet; import one.util.streamex.StreamEx; import org.jdom.Element; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; +import java.util.List; +import java.util.Map; import java.util.Set; /** * @author Pavel.Dolgov */ -public class Java9ModuleEntryPoint extends EntryPoint { +public class Java9ModuleEntryPoint extends EntryPointWithVisibilityLevel { + public static final String ID = "moduleInfo"; public boolean ADD_EXPORTED_PACKAGES_AND_SERVICES_TO_ENTRIES = true; @NotNull @@ -56,54 +60,126 @@ public class Java9ModuleEntryPoint extends EntryPoint { @Override public boolean isEntryPoint(@NotNull PsiElement psiElement) { if (psiElement instanceof PsiClass) { - return isExported((PsiClass)psiElement); + return isServiceOrExported((PsiClass)psiElement); } if (psiElement instanceof PsiMethod) { PsiMethod method = (PsiMethod)psiElement; if (isDefaultConstructor(method) || isProviderMethod(method)) { - return isExported(method.getContainingClass()); + return isServiceOrExported(method.getContainingClass()); } } return false; } - private static boolean isDefaultConstructor(PsiMethod method) { + @Override + public int getMinVisibilityLevel(PsiMember member) { + if (member instanceof PsiClass) { + final PsiJavaModule javaModule = getJavaModule(member); + if (javaModule != null && + !isServiceClass((PsiClass)member, javaModule) && + isInExportedPackage((PsiClass)member, javaModule)) { + return PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL; + } + } + return -1; + } + + @Override + public String getTitle() { + return "Suggest package-private visibility level for classes in exported packages (Java 9+)"; + } + + @Override + public String getId() { + return ID; + } + + @Override + public boolean keepVisibilityLevel(boolean entryPointEnabled, RefJavaElement refJavaElement) { + if (refJavaElement instanceof RefClass) { + RefClass refClass = (RefClass)refJavaElement; + RefModule refModule = refClass.getModule(); + if (refModule != null) { + RefJavaModule refJavaModule = RefJavaModule.JAVA_MODULE.get(refModule); + if (refJavaModule != null) { + return isServiceClass(refClass, refJavaModule) || + !entryPointEnabled && isInExportedPackage(refClass, refJavaModule); + } + } + } + return false; + } + + private static boolean isInExportedPackage(@Nullable RefClass refClass, @NotNull RefJavaModule refJavaModule) { + RefEntity refOwner = refClass; + while (refOwner instanceof RefClass) { + String modifier = ((RefClass)refOwner).getAccessModifier(); + refOwner = PsiModifier.PUBLIC.equals(modifier) || PsiModifier.PROTECTED.equals(modifier) ? refOwner.getOwner() : null; + } + if (refOwner instanceof RefPackage) { + Map> exportedPackageNames = refJavaModule.getExportedPackageNames(); + if (exportedPackageNames.containsKey(refOwner.getQualifiedName())) { + return true; + } + } + return false; + } + + private static boolean isServiceClass(@Nullable RefClass refClass, @NotNull RefJavaModule refJavaModule) { + return refJavaModule.getServiceInterfaces().contains(refClass) || + refJavaModule.getServiceImplementations().contains(refClass) || + refJavaModule.getUsedServices().contains(refClass); + } + + + private static boolean isDefaultConstructor(@NotNull PsiMethod method) { return method.isConstructor() && method.getParameterList().getParametersCount() == 0 && method.hasModifierProperty(PsiModifier.PUBLIC); } - private static boolean isProviderMethod(PsiMethod method) { + private static boolean isProviderMethod(@NotNull PsiMethod method) { return "provider".equals(method.getName()) && method.getParameterList().getParametersCount() == 0 && method.hasModifierProperty(PsiModifier.PUBLIC) && method.hasModifierProperty(PsiModifier.STATIC); } - private static boolean isExported(@Nullable PsiClass psiClass) { - if (psiClass != null) { - String className = psiClass.getQualifiedName(); - if (className != null) { - final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(psiClass); - if (languageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { - PsiJavaModule javaModule = JavaModuleGraphUtil.findDescriptorByElement(psiClass); - if (javaModule != null) { - String packageName = getPublicApiPackageName(psiClass); - if (packageName != null) { - Set exportedPackageNames = getExportedPackageNames(javaModule); - if (exportedPackageNames.contains(packageName)) { - return true; - } - } - Set serviceImplementationNames = getServiceImplementationNames(javaModule); - return serviceImplementationNames.contains(className); - } - } + private static boolean isServiceOrExported(@Nullable PsiClass psiClass) { + PsiJavaModule javaModule = getJavaModule(psiClass); + return javaModule != null && (isServiceClass(psiClass, javaModule) || isInExportedPackage(psiClass, javaModule)); + } + + private static boolean isInExportedPackage(@NotNull PsiClass psiClass, @NotNull PsiJavaModule javaModule) { + String packageName = getPublicApiPackageName(psiClass); + if (packageName != null) { + Set exportedPackageNames = getExportedPackageNames(javaModule); + if (exportedPackageNames.contains(packageName)) { + return true; } } return false; } + private static boolean isServiceClass(@NotNull PsiClass psiClass, @NotNull PsiJavaModule javaModule) { + Set serviceClassNames = CachedValuesManager.getCachedValue( + javaModule, () -> CachedValueProvider.Result.create(collectServiceClassNames(javaModule), javaModule)); + + return serviceClassNames.contains(psiClass.getQualifiedName()); + } + + @Contract("null -> null") + @Nullable + private static PsiJavaModule getJavaModule(@Nullable PsiElement element) { + if (element != null) { + final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(element); + if (languageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { + return JavaModuleGraphUtil.findDescriptorByElement(element); + } + } + return null; + } + private static String getPublicApiPackageName(PsiClass psiClass) { if (psiClass != null && (psiClass.hasModifierProperty(PsiModifier.PUBLIC) || psiClass.hasModifierProperty(PsiModifier.PROTECTED))) { PsiElement parent = psiClass.getParent(); @@ -128,18 +204,25 @@ public class Java9ModuleEntryPoint extends EntryPoint { } @NotNull - private static Set getServiceImplementationNames(@NotNull PsiJavaModule javaModule) { - return CachedValuesManager.getCachedValue(javaModule, () -> { - Set classes = StreamEx.of(javaModule.getProvides().iterator()) - .map(PsiProvidesStatement::getImplementationList) - .nonNull() - .map(PsiReferenceList::getReferenceElements) - .flatMap(Arrays::stream) - .map(PsiJavaCodeReferenceElement::getQualifiedName) - .nonNull() - .toCollection(THashSet::new); - return CachedValueProvider.Result.create(classes, javaModule); - }); + private static Set collectServiceClassNames(@NotNull PsiJavaModule javaModule) { + Set classes = StreamEx.of(javaModule.getProvides().spliterator()) + .map(PsiProvidesStatement::getImplementationList) + .nonNull() + .map(PsiReferenceList::getReferenceElements) + .flatMap(Arrays::stream) + .map(PsiJavaCodeReferenceElement::getQualifiedName) + .nonNull() + .toCollection(THashSet::new); + + Set usages = StreamEx.of(javaModule.getUses().iterator()) + .map(PsiUsesStatement::getClassReference) + .nonNull() + .map(PsiJavaCodeReferenceElement::getQualifiedName) + .nonNull() + .toCollection(THashSet::new); + + classes.addAll(usages); + return classes; } @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaModuleImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaModuleImpl.java index 71efaf4daba5..16e81f8d8854 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaModuleImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaModuleImpl.java @@ -33,7 +33,9 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule { private final RefModule myRefModule; private Map> myExportedPackageNames; + private Set myServiceInterfaces; private Set myServiceImplementations; + private Set myUsedServices; private List myRequiredModules; RefJavaModuleImpl(@NotNull PsiJavaModule javaModule, @NotNull RefManagerImpl manager) { @@ -75,104 +77,152 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule { return myExportedPackageNames != null ? myExportedPackageNames : Collections.emptyMap(); } + @NotNull + @Override + public Set getServiceInterfaces() { + return myServiceInterfaces != null ? myServiceInterfaces : Collections.emptySet(); + } + @NotNull @Override public Set getServiceImplementations() { return myServiceImplementations != null ? myServiceImplementations : Collections.emptySet(); } + @NotNull + @Override + public Set getUsedServices() { + return myUsedServices != null ? myUsedServices : Collections.emptySet(); + } + @Override @NotNull public List getRequiredModules() { return myRequiredModules != null ? myRequiredModules : Collections.emptyList(); } - @Override - public void buildReferences() { - PsiJavaModule javaModule = getElement(); - if (javaModule != null) { - for (PsiRequiresStatement statement : javaModule.getRequires()) { - PsiJavaModuleReferenceElement referenceElement = statement.getReferenceElement(); + private void buildRequiresReferences(PsiJavaModule javaModule) { + for (PsiRequiresStatement statement : javaModule.getRequires()) { + PsiJavaModuleReferenceElement referenceElement = statement.getReferenceElement(); + if (referenceElement != null) { + PsiElement element = addReference(referenceElement.getReference()); + if (element instanceof PsiJavaModule) { + PsiJavaModule requiredModule = (PsiJavaModule)element; + Map> packagesExportedByModule = getPackagesExportedByModule(requiredModule); + if (myRequiredModules == null) myRequiredModules = new ArrayList<>(1); + myRequiredModules.add(new RequiredModule(requiredModule.getName(), packagesExportedByModule, statement.hasModifierProperty(PsiModifier.TRANSITIVE))); + } + } + } + } + + private void buildExportsReferences(PsiJavaModule javaModule) { + List emptyList = Collections.emptyList(); + for (PsiPackageAccessibilityStatement statement : javaModule.getExports()) { + PsiElement element = addReference(statement.getPackageReference()); + String packageName = null; + if (element instanceof PsiPackage) { + packageName = ((PsiPackage)element).getQualifiedName(); + if (myExportedPackageNames == null) myExportedPackageNames = new THashMap<>(1); + myExportedPackageNames.put(packageName, emptyList); + } + for (PsiJavaModuleReferenceElement referenceElement : statement.getModuleReferences()) { if (referenceElement != null) { - PsiElement element = addReference(referenceElement.getReference()); - if (element instanceof PsiJavaModule) { - PsiJavaModule requiredModule = (PsiJavaModule)element; - Map> packagesExportedByModule = getPackagesExportedByModule(requiredModule); - if (myRequiredModules == null) myRequiredModules = new ArrayList<>(1); - myRequiredModules.add(new RequiredModule(requiredModule.getName(), packagesExportedByModule, statement.hasModifierProperty(PsiModifier.TRANSITIVE))); + PsiElement moduleElement = addReference(referenceElement.getReference()); + if (packageName != null && moduleElement instanceof PsiJavaModule) { + List toModuleNames = myExportedPackageNames.get(packageName); + if (toModuleNames == emptyList) myExportedPackageNames.put(packageName, toModuleNames = new ArrayList<>(1)); + toModuleNames.add(((PsiJavaModule)moduleElement).getName()); } } } - List emptyList = Collections.emptyList(); - for (PsiPackageAccessibilityStatement statement : javaModule.getExports()) { - PsiElement element = addReference(statement.getPackageReference()); - String packageName = null; - if (element instanceof PsiPackage) { - packageName = ((PsiPackage)element).getQualifiedName(); - if (myExportedPackageNames == null) myExportedPackageNames = new THashMap<>(1); - myExportedPackageNames.put(packageName, emptyList); - } - for (PsiJavaModuleReferenceElement referenceElement : statement.getModuleReferences()) { - if (referenceElement != null) { - PsiElement moduleElement = addReference(referenceElement.getReference()); - if (packageName != null && moduleElement instanceof PsiJavaModule) { - List toModuleNames = myExportedPackageNames.get(packageName); - if (toModuleNames == emptyList) myExportedPackageNames.put(packageName, toModuleNames = new ArrayList<>(1)); - toModuleNames.add(((PsiJavaModule)moduleElement).getName()); - } - } - } - } - for (PsiProvidesStatement statement : javaModule.getProvides()) { - final PsiJavaCodeReferenceElement interfaceReference = statement.getInterfaceReference(); - final PsiReferenceList implementationList = statement.getImplementationList(); - if (interfaceReference != null && implementationList != null) { - final PsiElement providerInterface = interfaceReference.resolve(); - if (providerInterface instanceof PsiClass) { - final RefElement refInterface = getRefManager().getReference(providerInterface); - if (refInterface instanceof RefJavaElementImpl) { - for (PsiJavaCodeReferenceElement implementationReference : implementationList.getReferenceElements()) { - final PsiElement implementationClass = implementationReference.resolve(); - if (implementationClass instanceof PsiClass) { - RefElement refTargetElement = null; - PsiElement targetElement = getProviderMethod((PsiClass)implementationClass); + } + } - if (targetElement == null) { - final RefElement refClass = getRefManager().getReference(implementationClass); - if (refClass instanceof RefClassImpl) { - if (myServiceImplementations == null) myServiceImplementations = new THashSet<>(); - myServiceImplementations.add((RefClass)refClass); + private void buildProvidesReferences(PsiJavaModule javaModule) { + for (PsiProvidesStatement statement : javaModule.getProvides()) { + final PsiJavaCodeReferenceElement interfaceReference = statement.getInterfaceReference(); + final PsiReferenceList implementationList = statement.getImplementationList(); + if (interfaceReference != null && implementationList != null) { + final PsiElement providerInterface = interfaceReference.resolve(); + if (providerInterface instanceof PsiClass) { + final RefElement refInterface = getRefManager().getReference(providerInterface); + if (refInterface instanceof RefClassImpl) { + if (myServiceInterfaces == null) myServiceInterfaces = new THashSet<>(); + myServiceInterfaces.add((RefClass)refInterface); - final RefMethod refConstructor = ((RefClassImpl)refClass).getDefaultConstructor(); - if (refConstructor != null) { - final PsiModifierListOwner constructorElement = refConstructor.getElement(); - if (constructorElement != null && constructorElement.hasModifierProperty(PsiModifier.PUBLIC)) { - refTargetElement = refConstructor; - targetElement = constructorElement; - } + for (PsiJavaCodeReferenceElement implementationReference : implementationList.getReferenceElements()) { + final PsiElement implementationClass = implementationReference.resolve(); + if (implementationClass instanceof PsiClass) { + RefElement refTargetElement = null; + PsiElement targetElement = getProviderMethod((PsiClass)implementationClass); + + if (targetElement == null) { + final RefElement refClass = getRefManager().getReference(implementationClass); + if (refClass instanceof RefClassImpl) { + if (myServiceImplementations == null) myServiceImplementations = new THashSet<>(); + myServiceImplementations.add((RefClass)refClass); + + final RefMethod refConstructor = ((RefClassImpl)refClass).getDefaultConstructor(); + if (refConstructor != null) { + final PsiModifierListOwner constructorElement = refConstructor.getElement(); + if (constructorElement != null && constructorElement.hasModifierProperty(PsiModifier.PUBLIC)) { + refTargetElement = refConstructor; + targetElement = constructorElement; } } } - if (targetElement == null) { - targetElement = implementationClass; - } - if (refTargetElement == null) { - refTargetElement = getRefManager().getReference(targetElement); - } - if (refTargetElement != null) { - ((RefJavaElementImpl)refInterface) - .addReference(refTargetElement, targetElement, providerInterface, false, true, null); - } + } + if (targetElement == null) { + targetElement = implementationClass; + } + if (refTargetElement == null) { + refTargetElement = getRefManager().getReference(targetElement); + } + if (refTargetElement != null) { + ((RefClassImpl)refInterface) + .addReference(refTargetElement, targetElement, providerInterface, false, true, null); } } } } } } + } + } + + private void buildUsesReferences(PsiJavaModule javaModule) { + for (PsiUsesStatement statement : javaModule.getUses()) { + final PsiJavaCodeReferenceElement reference = statement.getClassReference(); + if (reference != null) { + final PsiElement usedInterface = reference.resolve(); + if (usedInterface instanceof PsiClass) { + final RefElement refClass = getRefManager().getReference(usedInterface); + if (refClass instanceof RefClass) { + if (myUsedServices == null) myUsedServices = new THashSet<>(); + myUsedServices.add((RefClass)refClass); + } + } + } + } + } + + @Override + public void buildReferences() { + PsiJavaModule javaModule = getElement(); + if (javaModule != null) { + buildRequiresReferences(javaModule); + buildExportsReferences(javaModule); + buildProvidesReferences(javaModule); + buildUsesReferences(javaModule); + getRefManager().fireBuildReferences(this); } } + /** + * For building references between modules + */ private PsiElement addReference(PsiPolyVariantReference reference) { List resolvedElements = new ArrayList<>(); if (reference != null) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/EntryPointWithVisibilityLevel.java b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/EntryPointWithVisibilityLevel.java index 36a1e0ed4298..b57721487944 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/EntryPointWithVisibilityLevel.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/EntryPointWithVisibilityLevel.java @@ -16,7 +16,7 @@ package com.intellij.codeInspection.visibility; import com.intellij.codeInspection.reference.EntryPoint; -import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.codeInspection.reference.RefJavaElement; import com.intellij.psi.PsiMember; import com.intellij.psi.util.PsiUtil; @@ -39,4 +39,11 @@ public abstract class EntryPointWithVisibilityLevel extends EntryPoint { * Id to serialize checkbox state in visibility inspection settings */ public abstract String getId(); + + /** + * Don't suggest decreasing visibility for the element, sometimes even if the entry point is disabled. + */ + public boolean keepVisibilityLevel(boolean entryPointEnabled, @SuppressWarnings("unused") RefJavaElement refJavaElement) { + return false; + } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java index b64802ac94b2..6865cf828374 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java @@ -23,6 +23,7 @@ import com.intellij.codeInsight.daemon.impl.IdentifierUtil; import com.intellij.codeInspection.*; import com.intellij.codeInspection.ex.EntryPointsManager; import com.intellij.codeInspection.reference.*; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.ExtensionPoint; import com.intellij.openapi.extensions.ExtensionPointName; @@ -36,10 +37,12 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.ui.components.panels.VerticalBox; import com.intellij.usageView.UsageViewTypeLocation; import com.intellij.util.VisibilityUtil; +import one.util.streamex.StreamEx; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import javax.swing.*; import java.awt.*; @@ -101,7 +104,7 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { if (entryPoint instanceof EntryPointWithVisibilityLevel) { gc.gridy++; final JCheckBox checkBox = new JCheckBox(((EntryPointWithVisibilityLevel)entryPoint).getTitle()); - checkBox.setSelected(myExtensions.getOrDefault(((EntryPointWithVisibilityLevel)entryPoint).getId(), true)); + checkBox.setSelected(isEntryPointEnabled((EntryPointWithVisibilityLevel)entryPoint)); checkBox.addActionListener(e -> myExtensions.put(((EntryPointWithVisibilityLevel)entryPoint).getId(), checkBox.isSelected())); add(checkBox, gc); } @@ -181,11 +184,14 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { //ignore anonymous classes. They do not have access modifiers. if (refElement instanceof RefClass) { RefClass refClass = (RefClass) refElement; - if (refClass.isAnonymous() || refClass.isServlet() || refClass.isApplet() || refClass.isLocalClass() || isExported(refClass)) { + if (refClass.isAnonymous() || refClass.isServlet() || refClass.isApplet() || refClass.isLocalClass()) { return null; } } + if (keepVisibilityLevel(refElement)) { + return null; + } //ignore unreferenced code. They could be a potential entry points. if (refElement.getInReferences().isEmpty()) { @@ -215,30 +221,10 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { return null; } - private static boolean isExported(RefClass refClass) { - RefModule refModule = refClass.getModule(); - if (refModule != null) { - RefJavaModule refJavaModule = RefJavaModule.JAVA_MODULE.get(refModule); - if (refJavaModule != null) { - Set serviceImplementations = refJavaModule.getServiceImplementations(); - if (serviceImplementations.contains(refClass)) { - return true; - } - - RefEntity refOwner = refClass; - while (refOwner instanceof RefClass) { - String modifier = ((RefClass)refOwner).getAccessModifier(); - refOwner = PsiModifier.PUBLIC.equals(modifier) || PsiModifier.PROTECTED.equals(modifier) ? refOwner.getOwner() : null; - } - if (refOwner instanceof RefPackage) { - Map> exportedPackageNames = refJavaModule.getExportedPackageNames(); - if (exportedPackageNames.containsKey(refOwner.getQualifiedName())) { - return true; - } - } - } - } - return false; + private boolean keepVisibilityLevel(RefJavaElement refElement) { + return StreamEx.of(ExtensionPointName.create(ToolExtensionPoints.DEAD_CODE_TOOL).getExtensions()) + .select(EntryPointWithVisibilityLevel.class) + .anyMatch(point -> point.keepVisibilityLevel(isEntryPointEnabled(point), refElement)); } @NotNull @@ -273,13 +259,17 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { } int getMinVisibilityLevel(PsiMember member) { - return Arrays.stream(ExtensionPointName.create(ToolExtensionPoints.DEAD_CODE_TOOL).getExtensions()) - .filter(point -> point instanceof EntryPointWithVisibilityLevel && - myExtensions.getOrDefault(((EntryPointWithVisibilityLevel)point).getId(), true)) - .mapToInt(point -> ((EntryPointWithVisibilityLevel)point).getMinVisibilityLevel(member)) + return StreamEx.of(ExtensionPointName.create(ToolExtensionPoints.DEAD_CODE_TOOL).getExtensions()) + .select(EntryPointWithVisibilityLevel.class) + .filter(point -> isEntryPointEnabled(point)) + .mapToInt(point -> point.getMinVisibilityLevel(member)) .max().orElse(-1); } + private boolean isEntryPointEnabled(EntryPointWithVisibilityLevel point) { + return myExtensions.getOrDefault(point.getId(), true); + } + private int getMinVisibilityLevel(RefJavaElement refElement) { PsiElement element = refElement.getElement(); if (element instanceof PsiMember) { @@ -627,6 +617,12 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { } } + @TestOnly + public void setEntryPointEnabled(@NotNull String entryPointId, boolean enabled) { + LOG.assertTrue(ApplicationManager.getApplication().isUnitTestMode()); + myExtensions.put(entryPointId, enabled); + } + private static class AcceptSuggestedAccess implements LocalQuickFix{ private final RefManager myManager; @PsiModifier.ModifierConstant private final String myHint; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/wrongPackageStatement/WrongPackageStatementInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/wrongPackageStatement/WrongPackageStatementInspectionBase.java index 33a38f8bf6d2..ec0a9bd8ba4b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/wrongPackageStatement/WrongPackageStatementInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/wrongPackageStatement/WrongPackageStatementInspectionBase.java @@ -57,7 +57,7 @@ public class WrongPackageStatementInspectionBase extends BaseJavaBatchLocalInspe String description = JavaErrorMessages.message("missing.package.statement", packageName); return new ProblemDescriptor[]{manager.createProblemDescriptor(classes[0].getNameIdentifier(), description, - new AdjustPackageNameFix(packageName), + isValidPackageName(packageName, file.getProject()) ? new AdjustPackageNameFix(packageName) : null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly)}; } if (packageStatement != null) { diff --git a/java/java-impl/src/com/intellij/refactoring/actions/RenameFileActionImpl.java b/java/java-impl/src/com/intellij/refactoring/actions/RenameFileActionImpl.java new file mode 100644 index 000000000000..95e7b3bfd292 --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/actions/RenameFileActionImpl.java @@ -0,0 +1,27 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.refactoring.actions; + +import com.intellij.psi.PsiClassOwner; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +public class RenameFileActionImpl extends RenameFileAction { + @Override + protected boolean enabledInProjectView(@NotNull PsiFile file) { + return file instanceof PsiClassOwner; + } +} diff --git a/java/java-impl/src/com/intellij/slicer/SliceLeafAnalyzer.java b/java/java-impl/src/com/intellij/slicer/SliceLeafAnalyzer.java index 38370ba676f9..519661672530 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceLeafAnalyzer.java +++ b/java/java-impl/src/com/intellij/slicer/SliceLeafAnalyzer.java @@ -172,6 +172,7 @@ public class SliceLeafAnalyzer { public static Map> createMap() { return new FactoryMap>() { + @NotNull @Override protected Map> createMap() { return ContainerUtil.newConcurrentMap(ContainerUtil.identityStrategy()); diff --git a/java/java-impl/src/com/intellij/slicer/SliceNullnessAnalyzer.java b/java/java-impl/src/com/intellij/slicer/SliceNullnessAnalyzer.java index cd9e1535f00e..e0a6856c972b 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceNullnessAnalyzer.java +++ b/java/java-impl/src/com/intellij/slicer/SliceNullnessAnalyzer.java @@ -137,6 +137,7 @@ public class SliceNullnessAnalyzer { return new NullAnalysisResult(); } + @NotNull @Override protected Map createMap() { return ContainerUtil.newIdentityTroveMap(); diff --git a/java/java-impl/src/com/intellij/testIntegration/TestRunLineMarkerProvider.java b/java/java-impl/src/com/intellij/testIntegration/TestRunLineMarkerProvider.java index 81968ea62ab5..06d160c09092 100644 --- a/java/java-impl/src/com/intellij/testIntegration/TestRunLineMarkerProvider.java +++ b/java/java-impl/src/com/intellij/testIntegration/TestRunLineMarkerProvider.java @@ -16,12 +16,8 @@ package com.intellij.testIntegration; import com.intellij.codeInsight.TestFrameworks; -import com.intellij.execution.TestStateStorage; import com.intellij.execution.lineMarker.ExecutorAction; import com.intellij.execution.lineMarker.RunLineMarkerContributor; -import com.intellij.execution.testframework.TestIconMapper; -import com.intellij.execution.testframework.sm.runner.states.TestStateInfo; -import com.intellij.icons.AllIcons; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; @@ -73,23 +69,4 @@ public class TestRunLineMarkerProvider extends RunLineMarkerContributor { protected boolean isIdentifier(PsiElement e) { return e instanceof PsiIdentifier; } - - private static Icon getTestStateIcon(String url, Project project, boolean isClass) { - TestStateStorage.Record state = TestStateStorage.getInstance(project).getState(url); - if (state != null) { - TestStateInfo.Magnitude magnitude = TestIconMapper.getMagnitude(state.magnitude); - if (magnitude != null) { - switch (magnitude) { - case ERROR_INDEX: - case FAILED_INDEX: - return AllIcons.RunConfigurations.TestState.Red2; - case PASSED_INDEX: - case COMPLETE_INDEX: - return AllIcons.RunConfigurations.TestState.Green2; - default: - } - } - } - return isClass ? AllIcons.RunConfigurations.TestState.Run_run : AllIcons.RunConfigurations.TestState.Run; - } } diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearchHelper.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearchHelper.java index a1c32a4793f7..30d6a624d5fb 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearchHelper.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearchHelper.java @@ -18,6 +18,7 @@ package com.intellij.psi.impl.search; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.UnfairTextRange; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.light.LightMemberReference; @@ -258,6 +259,9 @@ class ConstructorReferencesSearchHelper { if (startOffsetInParent >= 0) { // -1 for light elements generated e.g. by lombok return TextRange.from(startOffsetInParent, identifier.getTextLength()); } + else { + return new UnfairTextRange(-1, -1); + } } } return super.getRangeInElement(); diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java index 6a1200c75ba7..04d9123f57d6 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java @@ -53,9 +53,11 @@ public class JavaOverridingMethodsSearcher implements QueryExecutor file.getFileType() == JavaFileType.INSTANCE)) { - return processLocalScope((LocalSearchScope)searchScope, method, project, consumer); + if (searchScope instanceof LocalSearchScope) { + VirtualFile[] files = ((LocalSearchScope)searchScope).getVirtualFiles(); + if (isJavaOnlyScope(files)) { + return processLocalScope((LocalSearchScope)searchScope, method, project, consumer); + } } Iterable cached = HighlightingCaches.getInstance(project).OVERRIDING_METHODS.get(method); @@ -79,6 +81,10 @@ public class JavaOverridingMethodsSearcher implements QueryExecutor file.getFileType() == JavaFileType.INSTANCE); + } + private static boolean processLocalScope(@NotNull LocalSearchScope searchScope, @NotNull PsiMethod method, @NotNull Project project, diff --git a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java index d84ff358f983..041a8f5036b4 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java @@ -86,13 +86,10 @@ public class AnnotationUtil { } private static PsiAnnotation findOwnAnnotation(final PsiModifierListOwner listOwner, Collection annotationNames) { - ConcurrentFactoryMap, PsiAnnotation> map = CachedValuesManager.getCachedValue( + Map, PsiAnnotation> map = CachedValuesManager.getCachedValue( listOwner, () -> { - ConcurrentFactoryMap, PsiAnnotation> value = new ConcurrentFactoryMap, PsiAnnotation>() { - @Nullable - @Override - protected PsiAnnotation create(Collection annotationNames1) { + Map, PsiAnnotation> value = ConcurrentFactoryMap.createConcurrentMap(annotationNames1-> { final PsiModifierList list = listOwner.getModifierList(); if (list == null) return null; for (PsiAnnotation annotation : list.getAnnotations()) { @@ -102,20 +99,17 @@ public class AnnotationUtil { } return null; } - }; + ); return CachedValueProvider.Result.create(value, PsiModificationTracker.MODIFICATION_COUNT); }); return map.get(annotationNames); } private static PsiAnnotation findNonCodeAnnotation(final PsiModifierListOwner listOwner, Collection annotationNames) { - ConcurrentFactoryMap, PsiAnnotation> map = CachedValuesManager.getCachedValue( + Map, PsiAnnotation> map = CachedValuesManager.getCachedValue( listOwner, () -> { - ConcurrentFactoryMap, PsiAnnotation> value = new ConcurrentFactoryMap, PsiAnnotation>() { - @Nullable - @Override - protected PsiAnnotation create(Collection annotationNames1) { + Map, PsiAnnotation> value = ConcurrentFactoryMap.createConcurrentMap(annotationNames1-> { final Project project = listOwner.getProject(); final ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(project); for (String annotationName : annotationNames1) { @@ -134,7 +128,7 @@ public class AnnotationUtil { return null; } - }; + ); return CachedValueProvider.Result.create(value, PsiModificationTracker.MODIFICATION_COUNT); }); return map.get(annotationNames); @@ -184,13 +178,11 @@ public class AnnotationUtil { PsiAnnotation directAnnotation = findAnnotation(listOwner, annotationNames); if (directAnnotation != null) return directAnnotation; - ConcurrentFactoryMap, PsiAnnotation> map = CachedValuesManager.getCachedValue( + Map, PsiAnnotation> map = CachedValuesManager.getCachedValue( listOwner, () -> { - ConcurrentFactoryMap, PsiAnnotation> value = new ConcurrentFactoryMap, PsiAnnotation>() { - @Nullable - @Override - protected PsiAnnotation create(Set annotationNames1) { + Map, PsiAnnotation> value = ConcurrentFactoryMap.createConcurrentMap(annotationNames1-> + { for (PsiModifierListOwner superOwner : getSuperAnnotationOwners(listOwner)) { PsiAnnotation annotation = findAnnotation(superOwner, annotationNames1); if (annotation != null) { @@ -199,7 +191,7 @@ public class AnnotationUtil { } return null; } - }; + ); return CachedValueProvider.Result.create(value, PsiModificationTracker.MODIFICATION_COUNT); }); return map.get(annotationNames); @@ -265,21 +257,30 @@ public class AnnotationUtil { } public static boolean isAnnotated(@NotNull PsiModifierListOwner listOwner, @NotNull String annotationFQN, boolean checkHierarchy) { - return isAnnotated(listOwner, annotationFQN, checkHierarchy, true, null); + return isAnnotated(listOwner, annotationFQN, checkHierarchy, true, true, null); } public static boolean isAnnotated(@NotNull PsiModifierListOwner listOwner, @NotNull String annotationFQN, boolean checkHierarchy, boolean skipExternal) { - return isAnnotated(listOwner, annotationFQN, checkHierarchy, skipExternal, null); + return isAnnotated(listOwner, annotationFQN, checkHierarchy, skipExternal, skipExternal); + } + + public static boolean isAnnotated(@NotNull PsiModifierListOwner listOwner, + @NotNull String annotationFQN, + boolean checkHierarchy, + boolean skipExternal, + boolean skipInferred) { + return isAnnotated(listOwner, annotationFQN, checkHierarchy, skipExternal, skipInferred, null); } private static boolean isAnnotated(@NotNull PsiModifierListOwner listOwner, - @NotNull String annotationFQN, - boolean checkHierarchy, - boolean skipExternal, - @Nullable Set processed) { + @NotNull String annotationFQN, + boolean checkHierarchy, + boolean skipExternal, + boolean skipInferred, + @Nullable Set processed) { if (!listOwner.isValid()) return false; PsiModifierList modifierList = listOwner.getModifierList(); @@ -289,14 +290,23 @@ public class AnnotationUtil { if (annotation != null) return true; PsiType type = null; - if (listOwner instanceof PsiMethod) type = ((PsiMethod)listOwner).getReturnType(); - else if (listOwner instanceof PsiVariable) type = ((PsiVariable)listOwner).getType(); + if (listOwner instanceof PsiMethod) { + type = ((PsiMethod)listOwner).getReturnType(); + } + else if (listOwner instanceof PsiVariable) { + type = ((PsiVariable)listOwner).getType(); + } if (type != null && type.findAnnotation(annotationFQN) != null) return true; if (!skipExternal) { final Project project = listOwner.getProject(); - if (ExternalAnnotationsManager.getInstance(project).findExternalAnnotation(listOwner, annotationFQN) != null || - InferredAnnotationsManager.getInstance(project).findInferredAnnotation(listOwner, annotationFQN) != null) { + if (ExternalAnnotationsManager.getInstance(project).findExternalAnnotation(listOwner, annotationFQN) != null) { + return true; + } + } + if (!skipInferred) { + final Project project = listOwner.getProject(); + if (InferredAnnotationsManager.getInstance(project).findInferredAnnotation(listOwner, annotationFQN) != null) { return true; } } @@ -308,7 +318,7 @@ public class AnnotationUtil { if (!processed.add(method)) return false; final PsiMethod[] superMethods = method.findSuperMethods(); for (PsiMethod superMethod : superMethods) { - if (isAnnotated(superMethod, annotationFQN, true, skipExternal, processed)) return true; + if (isAnnotated(superMethod, annotationFQN, true, skipExternal, skipInferred, processed)) return true; } } else if (listOwner instanceof PsiClass) { @@ -317,7 +327,7 @@ public class AnnotationUtil { if (!processed.add(clazz)) return false; final PsiClass[] superClasses = clazz.getSupers(); for (PsiClass superClass : superClasses) { - if (isAnnotated(superClass, annotationFQN, true, skipExternal, processed)) return true; + if (isAnnotated(superClass, annotationFQN, true, skipExternal, skipInferred, processed)) return true; } } } @@ -536,7 +546,7 @@ public class AnnotationUtil { if (a == null) { return b == null; } - else if (b == null) { + if (b == null) { return false; } final String name = a.getQualifiedName(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/annotateMethod/afterOverriddenWithInferred.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/annotateMethod/afterOverriddenWithInferred.java new file mode 100644 index 000000000000..14a463bb4b07 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/annotateMethod/afterOverriddenWithInferred.java @@ -0,0 +1,18 @@ +// "Annotate overridden methods as '@NotNull'" "true" + +import org.jetbrains.annotations.NotNull; + +abstract class P2 { + @NotNull + String foo(@NotNull String p) { + return p; + } + + Object o = new P2() { + @NotNull + @Override + String foo(String p) { + return ""; + } + }; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/annotateMethod/beforeOverriddenWithInferred.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/annotateMethod/beforeOverriddenWithInferred.java new file mode 100644 index 000000000000..343fc019c121 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/annotateMethod/beforeOverriddenWithInferred.java @@ -0,0 +1,17 @@ +// "Annotate overridden methods as '@NotNull'" "true" + +import org.jetbrains.annotations.NotNull; + +abstract class P2 { + @NotNull + String foo(@NotNull String p) { + return p; + } + + Object o = new P2() { + @Override + String foo(String p) { + return ""; + } + }; +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/Public.java b/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/Public.java new file mode 100644 index 000000000000..69dda4039633 --- /dev/null +++ b/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/Public.java @@ -0,0 +1,3 @@ +package foo.bar; + +public class Public {} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/ServiceApi.java b/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/ServiceApi.java new file mode 100644 index 000000000000..7fd656840fcc --- /dev/null +++ b/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/ServiceApi.java @@ -0,0 +1,3 @@ +package foo.bar; + +public class ServiceApi {} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/ServiceImpl.java b/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/ServiceImpl.java new file mode 100644 index 000000000000..16a1a3626aec --- /dev/null +++ b/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/ServiceImpl.java @@ -0,0 +1,3 @@ +package foo.bar; + +public class ServiceImpl extends ServiceApi {} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/UsedService.java b/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/UsedService.java new file mode 100644 index 000000000000..e737a4be4fd0 --- /dev/null +++ b/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/UsedService.java @@ -0,0 +1,3 @@ +package foo.bar; + +public class UsedService {} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/expected.xml b/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/expected.xml new file mode 100644 index 000000000000..8e068179635c --- /dev/null +++ b/java/java-tests/testData/inspection/java9Visibility/reduceVisibilityInExportedPackages/expected.xml @@ -0,0 +1,10 @@ + + + + Public.java + 3 + + Declaration access can be weaker + Can be package-private + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/java9Visibility/usedService/Api.java b/java/java-tests/testData/inspection/java9Visibility/usedService/Api.java new file mode 100644 index 000000000000..417e6f7a08f1 --- /dev/null +++ b/java/java-tests/testData/inspection/java9Visibility/usedService/Api.java @@ -0,0 +1,3 @@ +package foo.bar; + +public class Api {} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/java9Visibility/usedService/Impl.java b/java/java-tests/testData/inspection/java9Visibility/usedService/Impl.java new file mode 100644 index 000000000000..a700ddc5ed2c --- /dev/null +++ b/java/java-tests/testData/inspection/java9Visibility/usedService/Impl.java @@ -0,0 +1,4 @@ +package foo.bar.impl; +import foo.bar Api; + +public class Impl extends Api {} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/java9Visibility/usedService/Other.java b/java/java-tests/testData/inspection/java9Visibility/usedService/Other.java new file mode 100644 index 000000000000..5e7f2d1881ce --- /dev/null +++ b/java/java-tests/testData/inspection/java9Visibility/usedService/Other.java @@ -0,0 +1,4 @@ +package foo.bar.impl; +import foo.bar Api; + +public class Other extends Api {} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/java9Visibility/usedService/expected.xml b/java/java-tests/testData/inspection/java9Visibility/usedService/expected.xml new file mode 100644 index 000000000000..161b0b37a534 --- /dev/null +++ b/java/java-tests/testData/inspection/java9Visibility/usedService/expected.xml @@ -0,0 +1,10 @@ + + + + Other.java + 4 + + Declaration access can be weaker + Can be package-private + + \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/AnnotateMethodTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/AnnotateMethodTest.java index f49118c787f5..9ffde57cf7fe 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/AnnotateMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/AnnotateMethodTest.java @@ -67,3 +67,16 @@ public class AnnotateMethodTest extends LightQuickFixTestCase { return LanguageLevel.JDK_1_5; } } +abstract class P2 { + @NotNull + String foo(@NotNull String p) { + return p; + } + + Object o = new P2() { + @Override + String foo(String p) { + return ""; + } + }; +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/folding/JavaFoldingTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/folding/JavaFoldingTest.groovy index c4965f48891d..ce287323f6a5 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/folding/JavaFoldingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/folding/JavaFoldingTest.groovy @@ -27,10 +27,10 @@ import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.editor.FoldRegion import com.intellij.openapi.editor.ex.DocumentEx import com.intellij.openapi.editor.ex.EditorEx +import com.intellij.openapi.editor.ex.FoldingListener import com.intellij.openapi.editor.ex.FoldingModelEx import com.intellij.openapi.editor.impl.FoldingModelImpl import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider -import com.intellij.openapi.util.registry.Registry import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiClass import com.intellij.psi.PsiMethod @@ -841,36 +841,6 @@ class Foo { assertEquals 3, expandedFoldRegionsCount } - public void "test single line closure unfolds when converted to multiline"() { - boolean oldValue = Registry.is("editor.durable.folding.state") - try { - Registry.get("editor.durable.folding.state").setValue(false) - - @Language("JAVA") - def text = """ - class Foo { - void m() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - System.out.println(); - } - }); - } - } - """ - configure text - assert myFixture.editor.foldingModel.getCollapsedRegionAtOffset(text.indexOf("new Runnable")) - myFixture.editor.caretModel.moveToOffset(text.indexOf("System")) - myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ENTER) - myFixture.doHighlighting() - assert myFixture.editor.foldingModel.getCollapsedRegionAtOffset(text.indexOf("new Runnable")) == null - } - finally { - Registry.get("editor.durable.folding.state").setValue(oldValue) - } - } - public void "test folding state is preserved for unchanged text in bulk mode"() { @Language("JAVA") def text = """ @@ -1083,6 +1053,37 @@ class Foo { } } + public void testGroupedFoldingsAreNotUpdatedOnUnrelatedDocumentChange() throws Exception { + configure """\ +class Foo { + void m() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + System.out.println(); + } + }); + } +} +""" + assertTopLevelFoldRegionsState "[FoldRegion +(56:143), placeholder='(Runnable) () → { ', FoldRegion +(164:188), placeholder=' }']" + + (myFixture.editor.foldingModel as FoldingModelEx).addListener(new FoldingListener() { + @Override + void onFoldRegionStateChange(@NotNull FoldRegion region) { + fail "Unexpected fold region change" + } + + @Override + void onFoldProcessingEnd() { + fail "Unexpected fold regions change" + } + }, myFixture.testRootDisposable) + myFixture.editor.caretModel.moveToOffset(myFixture.editor.document.text.indexOf("SwingUtilities")) + myFixture.type(' ') + myFixture.doHighlighting() + } + private void assertTopLevelFoldRegionsState(String expectedState) { assertEquals(expectedState, myFixture.editor.foldingModel.toString()) } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/Java9VisibilityTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInspection/Java9VisibilityTest.kt index 3ff360804f72..ecd67d3e589d 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/Java9VisibilityTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/Java9VisibilityTest.kt @@ -16,6 +16,7 @@ package com.intellij.java.codeInspection import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper +import com.intellij.codeInspection.java19modules.Java9ModuleEntryPoint import com.intellij.codeInspection.visibility.VisibilityInspection import com.intellij.java.testFramework.fixtures.LightJava9ModulesCodeInsightFixtureTestCase import com.intellij.openapi.application.ex.PathManagerEx @@ -33,6 +34,21 @@ class Java9VisibilityTest : LightJava9ModulesCodeInsightFixtureTestCase() { fun testInheritedService() = doTestService() fun testProvidedService() = doTestService() + fun testUsedService() { + moduleInfo("module foo.bar { exports foo.bar; uses foo.bar.Api; uses foo.bar.impl.Impl; }") + doTest("foo.bar.Api", "foo.bar.impl.Impl", "foo.bar.impl.Other") + } + + fun testReduceVisibilityInExportedPackages() { + moduleInfo("""module foo.bar { + exports foo.bar; + provides foo.bar.ServiceApi with foo.bar.ServiceImpl; + uses foo.bar.UsedService; +}""") + doTest("foo.bar.Public", "foo.bar.ServiceApi", "foo.bar.ServiceImpl", "foo.bar.UsedService", + reduceVisibilityInExportedPackages = true) + } + private fun doTestClass() { moduleInfo("module foo.bar { exports foo.bar; }") doTest("foo.bar.Api", "foo.bar.impl.Impl") @@ -43,11 +59,14 @@ class Java9VisibilityTest : LightJava9ModulesCodeInsightFixtureTestCase() { doTest("foo.bar.Api", "foo.bar.impl.Impl", "foo.bar.impl.Other") } - private fun doTest(vararg classNames: String) { + private fun doTest(vararg classNames: String, reduceVisibilityInExportedPackages: Boolean = false) { val testPath = testDataPath + getTestName(true) addJavaFiles(testPath, classNames) - val toolWrapper = GlobalInspectionToolWrapper(VisibilityInspection()) + val inspection = VisibilityInspection() + inspection.setEntryPointEnabled(Java9ModuleEntryPoint.ID, reduceVisibilityInExportedPackages) + + val toolWrapper = GlobalInspectionToolWrapper(inspection) doGlobalInspectionTest(testPath, toolWrapper) } } diff --git a/java/java-tests/testSrc/com/intellij/java/propertyBased/PsiIndexConsistencyTest.kt b/java/java-tests/testSrc/com/intellij/java/propertyBased/PsiIndexConsistencyTest.kt index c6403e603d38..6d4249e42810 100644 --- a/java/java-tests/testSrc/com/intellij/java/propertyBased/PsiIndexConsistencyTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/propertyBased/PsiIndexConsistencyTest.kt @@ -16,6 +16,7 @@ package com.intellij.java.propertyBased import com.intellij.java.propertyBased.PsiIndexConsistencyTest.Action.* +import com.intellij.lang.java.lexer.JavaLexer import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.vfs.VfsUtil @@ -55,7 +56,7 @@ class PsiIndexConsistencyTest: LightCodeInsightFixtureTestCase() { 10 to Generator.sampledFrom(*RefKind.values()).map { LoadRef(it) }, 10 to Generator.sampledFrom(*RefKind.values()).map { ClearRef(it) }, 5 to Generator.booleans().map { ChangeLanguageLevel(if (it) LanguageLevel.HIGHEST else LanguageLevel.JDK_1_3) }, - 5 to Generator.from { data -> TextChange(Generator.asciiIdentifiers().generateValue(data), + 5 to Generator.from { data -> TextChange(Generator.asciiIdentifiers().suchThat { !JavaLexer.isKeyword(it, LanguageLevel.HIGHEST) }.generateValue(data), Generator.booleans().generateValue(data), Generator.booleans().generateValue(data)) } )) diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java index 5388f718a37e..4bf7a9ca4b11 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java @@ -34,6 +34,7 @@ import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.tools.*; +import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -116,7 +117,7 @@ final class JavacReferenceCollectorListener implements TaskListener { if (e.getKind() == TaskEvent.Kind.ANALYZE) { // javac creates an event on each processed top level declared class not file final CompilationUnitTree unit = e.getCompilationUnit(); - final String fileName = e.getSourceFile().toUri().getPath(); + final String fileName = new File(e.getSourceFile().toUri().getPath()).getPath(); Tree declarationToProcess = myTreeUtility.getTree(e.getTypeElement()); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/internal/AssertionMethodImpl.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/internal/AssertionMethodImpl.java index ac8ca5eab391..c3e39f8c2106 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/internal/AssertionMethodImpl.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/internal/AssertionMethodImpl.java @@ -16,14 +16,13 @@ package org.jetbrains.jps.incremental.instrumentation.internal; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.SystemInfo; /* A template for the synthetic method embedded by the bytecode instrumentation. */ class AssertionMethodImpl { private static void assertArgumentIsSystemIndependent(String className, String methodName, String parameterName, String argument) { - if (SystemInfo.isWindows && argument != null && argument.contains("\\")) { + if (argument != null && argument.indexOf('\\') > -1) { String message = String.format("Argument for @SystemIndependent parameter '%s' of %s.%s must be system-independent: %s", parameterName, className, methodName, argument); diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java index 799ea2508ed9..0d9cfdaf76d9 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java @@ -26,6 +26,7 @@ import com.intellij.psi.PsiElement; import com.intellij.util.ObjectUtils; import com.intellij.util.SmartList; import com.intellij.util.ThreeState; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker; import com.jetbrains.jsonSchema.extension.adapters.JsonArrayValueAdapter; @@ -43,6 +44,8 @@ import java.util.stream.Collectors; * @author Irina.Chernushina on 4/25/2017. */ class JsonSchemaAnnotatorChecker { + private static final Set PRIMITIVE_TYPES = + ContainerUtil.set(JsonSchemaType._integer, JsonSchemaType._number, JsonSchemaType._boolean, JsonSchemaType._string, JsonSchemaType._null); private final Map myErrors; private boolean myHadTypeError; @@ -351,13 +354,12 @@ class JsonSchemaAnnotatorChecker { } private static boolean areSchemaTypesCompatible(@NotNull final JsonSchemaObject schema, @NotNull final JsonSchemaType type) { - if (getMatchingSchemaType(schema, type) != null) return true; - if (schema.getEnum() != null && (JsonSchemaType._integer.equals(type) || - JsonSchemaType._number.equals(type) || JsonSchemaType._boolean.equals(type) || - JsonSchemaType._string.equals(type))) { - return true; + if (schema.getEnum() != null) { + return PRIMITIVE_TYPES.contains(type); } - return false; + final JsonSchemaType matchingSchemaType = getMatchingSchemaType(schema, type); + if (matchingSchemaType != null) return matchingSchemaType.equals(type); + return true; } @Nullable @@ -550,7 +552,7 @@ class JsonSchemaAnnotatorChecker { private JsonSchemaObject processOneOf(@NotNull JsonValueAdapter value, List oneOf) { final Map errors = new HashMap<>(); boolean wasTypeError = false; - int cntCorrect = 0; + final List correct = new SmartList<>(); JsonSchemaObject current = null; for (JsonSchemaObject object : oneOf) { // skip it if something JS awaited, we do not process it currently @@ -562,7 +564,7 @@ class JsonSchemaAnnotatorChecker { if (checker.isCorrect()) { current = object; errors.clear(); - ++cntCorrect; + correct.add(object); } else { if (errors.isEmpty() || wasTypeError && !checker.isHadTypeError() || errors.size() > checker.getErrors().size()) { @@ -573,10 +575,15 @@ class JsonSchemaAnnotatorChecker { } } } - if (cntCorrect == 1) return current; - if (cntCorrect > 0) { + if (correct.size() == 1) return current; + if (correct.size() > 0) { final JsonSchemaType type = JsonSchemaType.getType(value); - if (type != null) error("Validates to more than one variant", value.getDelegate()); + if (type != null) { + // also check maybe some currently not checked properties like format are different with schemes + if (!schemesDifferWithNotCheckedProperties(correct)) { + error("Validates to more than one variant", value.getDelegate()); + } + } } else { if (!errors.isEmpty()) { @@ -588,6 +595,10 @@ class JsonSchemaAnnotatorChecker { return current; } + private static boolean schemesDifferWithNotCheckedProperties(@NotNull final List list) { + return list.stream().anyMatch(s -> !StringUtil.isEmptyOrSpaces(s.getFormat())); + } + // returns the schema, selected for annotation private JsonSchemaObject processAnyOf(@NotNull JsonValueAdapter value, List anyOf) { final Map errors = new HashMap<>(); diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaCompletionContributor.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaCompletionContributor.java index 749064ab01a6..8b0a752eef7e 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaCompletionContributor.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaCompletionContributor.java @@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.Consumer; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker; import com.jetbrains.jsonSchema.extension.JsonSchemaFileProvider; @@ -210,13 +211,13 @@ public class JsonSchemaCompletionContributor extends CompletionContributor { } private void addPropertyVariant(@NotNull String key, @NotNull JsonSchemaObject jsonSchemaObject, boolean hasValue, boolean insertComma) { - final String description = jsonSchemaObject.getDescription(); - final String title = jsonSchemaObject.getTitle(); + jsonSchemaObject = ObjectUtils.coalesce(ContainerUtil.getFirstItem(new JsonSchemaResolver(jsonSchemaObject).resolve()), + jsonSchemaObject); key = !myWrapInQuotes ? key : StringUtil.wrapWithDoubleQuote(key); LookupElementBuilder builder = LookupElementBuilder.create(key); - String typeText = StringUtil.isEmpty(title) ? description : title; - if (!StringUtil.isEmpty(typeText)) { + final String typeText = StringUtil.escapeXml(jsonSchemaObject.getDocumentation(true)); + if (!StringUtil.isEmptyOrSpaces(typeText)) { builder = builder.withTypeText(typeText, true); } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaDocumentationProvider.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaDocumentationProvider.java index c866e1e02346..b399cd843109 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaDocumentationProvider.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaDocumentationProvider.java @@ -1,15 +1,11 @@ package com.jetbrains.jsonSchema.impl; -import com.intellij.json.psi.JsonObject; -import com.intellij.json.psi.JsonProperty; -import com.intellij.json.psi.JsonStringLiteral; -import com.intellij.json.psi.JsonValue; import com.intellij.lang.documentation.DocumentationProvider; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; -import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.ObjectUtils; import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker; import com.jetbrains.jsonSchema.ide.JsonSchemaService; import org.jetbrains.annotations.NotNull; @@ -23,7 +19,7 @@ public class JsonSchemaDocumentationProvider implements DocumentationProvider { @Nullable @Override public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { - return null; + return findSchemaAndGenerateDoc(element, originalElement, true); } @Nullable @@ -35,21 +31,24 @@ public class JsonSchemaDocumentationProvider implements DocumentationProvider { @Nullable @Override public String generateDoc(PsiElement element, @Nullable PsiElement originalElement) { + return findSchemaAndGenerateDoc(element, originalElement, false); + } + + @Nullable + private static String findSchemaAndGenerateDoc(PsiElement element, @Nullable PsiElement originalElement, final boolean preferShort) { + element = ObjectUtils.coalesce(originalElement, element); final PsiFile containingFile = element.getContainingFile(); if (containingFile == null) return null; final JsonSchemaService service = JsonSchemaService.Impl.get(element.getProject()); final JsonSchemaObject rootSchema = service.getSchemaObject(containingFile.getViewProvider().getVirtualFile()); if (rootSchema == null) return null; - if (JsonSchemaService.isSchemaFile(containingFile)) { - return generateForJsonSchemaFileType(element); - } - return generateDoc(element, rootSchema); + return generateDoc(element, rootSchema, preferShort); } @Nullable public static String generateDoc(@NotNull final PsiElement element, - @NotNull final JsonSchemaObject rootSchema) { + @NotNull final JsonSchemaObject rootSchema, final boolean preferShort) { final JsonLikePsiWalker walker = JsonLikePsiWalker.getWalker(element, rootSchema); if (walker == null) return null; @@ -59,24 +58,8 @@ public class JsonSchemaDocumentationProvider implements DocumentationProvider { final Collection schemas = new JsonSchemaResolver(rootSchema, true, position).resolve(); - return schemas.stream().filter(schema -> !StringUtil.isEmptyOrSpaces(schema.getDescription())) - .findFirst().map(JsonSchemaObject::getDescription).orElse(null); - } - - @Nullable - private static String generateForJsonSchemaFileType(@NotNull PsiElement element) { - final JsonProperty jsonProperty = - element instanceof JsonProperty ? (JsonProperty)element : PsiTreeUtil.getParentOfType(element, JsonProperty.class); - if (jsonProperty != null) { - final JsonValue value = jsonProperty.getValue(); - if (value instanceof JsonObject) { - final JsonProperty description = ((JsonObject)value).findProperty("description"); - if (description != null && description.getValue() instanceof JsonStringLiteral) { - return StringUtil.escapeXml(StringUtil.unquoteString(description.getValue().getText())); - } - } - } - return null; + return StringUtil.escapeXml(schemas.stream().filter(schema -> !StringUtil.isEmptyOrSpaces(schema.getDocumentation(preferShort))) + .findFirst().map(schema -> schema.getDocumentation(preferShort)).orElse(null)); } @Nullable diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java index 6a413de23d00..b531bfe4a3e0 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java @@ -87,7 +87,7 @@ public class JsonSchemaObject { // peer pointer is not merged! public void mergeValues(JsonSchemaObject other) { - // we do not copy id, schema, title and description + // we do not copy id, schema myProperties.putAll(other.myProperties); myDefinitionsMap = copyMap(myDefinitionsMap, other.myDefinitionsMap); @@ -95,6 +95,9 @@ public class JsonSchemaObject { other.myPatternProperties == null ? null : other.myPatternProperties.mySchemasMap); myPatternProperties = map == null ? null : new PatternProperties(map); + if (!StringUtil.isEmptyOrSpaces(other.myTitle)) { + myTitle = other.myTitle; + } if (!StringUtil.isEmptyOrSpaces(other.myDescription)) { myDescription = other.myDescription; } @@ -548,6 +551,12 @@ public class JsonSchemaObject { return current; } + @Nullable + public String getDocumentation(final boolean preferShort) { + if (preferShort) return StringUtil.isEmptyOrSpaces(myTitle) ? myDescription : myTitle; + return StringUtil.isEmptyOrSpaces(myDescription) ? myTitle : myDescription; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaResolver.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaResolver.java index 169821a805cb..2f635c73dc09 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaResolver.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaResolver.java @@ -54,6 +54,7 @@ public class JsonSchemaResolver { return MatchResult.create(node); } + @NotNull public Collection resolve() { return resolve(false, false, false); } diff --git a/json/tests/test/com/jetbrains/jsonSchema/JsonBySchemaDocumentationBaseTest.java b/json/tests/test/com/jetbrains/jsonSchema/JsonBySchemaDocumentationBaseTest.java index 191fa9ba56e2..1cd2dea2fa74 100644 --- a/json/tests/test/com/jetbrains/jsonSchema/JsonBySchemaDocumentationBaseTest.java +++ b/json/tests/test/com/jetbrains/jsonSchema/JsonBySchemaDocumentationBaseTest.java @@ -20,8 +20,10 @@ import com.intellij.json.JsonLanguage; import com.intellij.lang.LanguageDocumentation; import com.intellij.lang.documentation.DocumentationProvider; import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiUtilBase; import com.jetbrains.jsonSchema.impl.JsonSchemaDocumentationProvider; import org.jetbrains.annotations.NotNull; +import org.junit.Assert; import java.util.ArrayList; @@ -52,7 +54,8 @@ public abstract class JsonBySchemaDocumentationBaseTest extends JsonSchemaHeavyA @Override public void doCheck() { - PsiElement psiElement = DocumentationManager.getInstance(getProject()).findTargetElement(myEditor, myFile); + final PsiElement psiElement = PsiUtilBase.getElementAtCaret(myEditor); + Assert.assertNotNull(psiElement); assertDocumentation(psiElement, psiElement, hasDoc); } }); @@ -65,6 +68,12 @@ public abstract class JsonBySchemaDocumentationBaseTest extends JsonSchemaHeavyA protected void assertDocumentation(@NotNull PsiElement docElement, @NotNull PsiElement context, boolean shouldHaveDoc) { DocumentationProvider documentationProvider = DocumentationManager.getProviderFromElement(context); String inlineDoc = documentationProvider.generateDoc(docElement, context); + String quickNavigate = documentationProvider.getQuickNavigateInfo(docElement, context); + checkExpectedDoc(shouldHaveDoc, inlineDoc, false); + checkExpectedDoc(shouldHaveDoc, quickNavigate, true); + } + + private void checkExpectedDoc(boolean shouldHaveDoc, String inlineDoc, boolean preferShort) { if (shouldHaveDoc) { assertNotNull("inline help is null", inlineDoc); } @@ -72,7 +81,7 @@ public abstract class JsonBySchemaDocumentationBaseTest extends JsonSchemaHeavyA assertNull("inline help is not null", inlineDoc); } if (shouldHaveDoc) { - assertSameLinesWithFile(getTestDataPath() + "/" + getTestName(true) + ".html", inlineDoc); + assertSameLinesWithFile(getTestDataPath() + "/" + getTestName(true) + (preferShort ? "_short.html" : ".html"), inlineDoc); } } } diff --git a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaDocumentationTest.java b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaDocumentationTest.java index b7f47cb68571..88e69f8823ba 100644 --- a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaDocumentationTest.java +++ b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaDocumentationTest.java @@ -32,4 +32,12 @@ public class JsonSchemaDocumentationTest extends JsonBySchemaDocumentationBaseTe public void testCheckEscaping() throws Exception { doTest(true, "json"); } + + public void testWithDefinition() throws Exception { + doTest(true, "json"); + } + + public void testWithTitleInDefinition() throws Exception { + doTest(true, "json"); + } } diff --git a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java index 7ff84fa0126f..62763ba31810 100644 --- a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java +++ b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java @@ -305,8 +305,8 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase { final String subSchema1 = "{\"enum\": [1,2,3,4,5]}"; final String subSchema2 = "{\"type\": \"array\", \"items\": {\"properties\": {\"kilo\": {}}, \"additionalProperties\": false}}"; final String schema = "{\"properties\": {\"prop\": {\"oneOf\": [" + subSchema1 + ", " + subSchema2 + "]}}}"; - doTest(schema, "{\"prop\": [{\"kilo\": 20}]}"); - doTest(schema, "{\"prop\": 5}"); + //doTest(schema, "{\"prop\": [{\"kilo\": 20}]}"); + //doTest(schema, "{\"prop\": 5}"); doTest(schema, "{\"prop\": [{\"foxtrot\": 15, \"kilo\": 20}]}"); } @@ -512,6 +512,45 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase { doTest(schema, "{\"not_type\": \"4a4\"}"); } + public void testDoNotMarkOneOfThatDiffersWithFormat() throws Exception { + final String schema = "{\n" + + "\n" + + " \"properties\": {\n" + + " \"withFormat\": {\n" + + " \"type\": \"string\"," + + " \"oneOf\": [\n" + + " {\n" + + " \"format\":\"hostname\"\n" + + " },\n" + + " {\n" + + " \"format\": \"ip4\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + "}"; + doTest(schema, "{\"withFormat\": \"localhost\"}"); + } + + public void testAcceptSchemaWithoutType() throws Exception { + final String schema = "{\n" + + "\n" + + " \"properties\": {\n" + + " \"withFormat\": {\n" + + " \"oneOf\": [\n" + + " {\n" + + " \"format\":\"hostname\"\n" + + " },\n" + + " {\n" + + " \"format\": \"ip4\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + "}"; + doTest(schema, "{\"withFormat\": \"localhost\"}"); + } + public static String rootObjectRedefinedSchema() { return "{\n" + " \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n" + diff --git a/json/tests/test/com/jetbrains/jsonSchema/impl/JsonBySchemaCompletionTest.java b/json/tests/test/com/jetbrains/jsonSchema/impl/JsonBySchemaCompletionTest.java index fe2072a64959..631165f20686 100644 --- a/json/tests/test/com/jetbrains/jsonSchema/impl/JsonBySchemaCompletionTest.java +++ b/json/tests/test/com/jetbrains/jsonSchema/impl/JsonBySchemaCompletionTest.java @@ -1,7 +1,9 @@ package com.jetbrains.jsonSchema.impl; +import com.intellij.codeInsight.lookup.LookupElementPresentation; import com.jetbrains.jsonSchema.JsonSchemaHighlightingTest; import org.jetbrains.annotations.NotNull; +import org.junit.Assert; /** * @author Irina.Chernushina on 10/1/2015. @@ -157,6 +159,47 @@ public class JsonBySchemaCompletionTest extends JsonBySchemaCompletionBaseTest { testImpl(schema, "{\"null\": }", "false", "null", "true"); } + public void testDescriptionFromDefinitionInCompletion() throws Exception { + final String schema = "{\n" + + " \"definitions\": {\n" + + " \"target\": {\n" + + " \"description\": \"Target description\"\n" + + " }\n" + + " },\n" + + " \"properties\": {\n" + + " \"source\": {\n" + + " \"$ref\": \"#/definitions/target\"\n" + + " }\n" + + " }\n" + + "}"; + testImpl(schema, "{}", "\"source\""); + Assert.assertEquals(1, myItems.length); + final LookupElementPresentation presentation = new LookupElementPresentation(); + myItems[0].renderElement(presentation); + Assert.assertEquals("Target description", presentation.getTypeText()); + } + + public void testDescriptionFromTitleInCompletion() throws Exception { + final String schema = "{\n" + + " \"definitions\": {\n" + + " \"target\": {\n" + + " \"title\": \"Target title\",\n" + + " \"description\": \"Target description\"\n" + + " }\n" + + " },\n" + + " \"properties\": {\n" + + " \"source\": {\n" + + " \"$ref\": \"#/definitions/target\"\n" + + " }\n" + + " }\n" + + "}"; + testImpl(schema, "{}", "\"source\""); + Assert.assertEquals(1, myItems.length); + final LookupElementPresentation presentation = new LookupElementPresentation(); + myItems[0].renderElement(presentation); + Assert.assertEquals("Target title", presentation.getTypeText()); + } + @NotNull private static String parcelShopSchema() { return "{\n" + diff --git a/json/tests/testData/jsonSchema/documentation/checkEscaping_short.html b/json/tests/testData/jsonSchema/documentation/checkEscaping_short.html new file mode 100644 index 000000000000..c73fc4ac3bd3 --- /dev/null +++ b/json/tests/testData/jsonSchema/documentation/checkEscaping_short.html @@ -0,0 +1 @@ +Disallows /// <reference path=> imports (use ES6-style imports instead) \ No newline at end of file diff --git a/json/tests/testData/jsonSchema/documentation/secondLevel_short.html b/json/tests/testData/jsonSchema/documentation/secondLevel_short.html new file mode 100644 index 000000000000..888aa3fb0ae8 --- /dev/null +++ b/json/tests/testData/jsonSchema/documentation/secondLevel_short.html @@ -0,0 +1 @@ +my second level property description 1 \ No newline at end of file diff --git a/json/tests/testData/jsonSchema/documentation/simple_short.html b/json/tests/testData/jsonSchema/documentation/simple_short.html new file mode 100644 index 000000000000..c4941ce9e4db --- /dev/null +++ b/json/tests/testData/jsonSchema/documentation/simple_short.html @@ -0,0 +1 @@ +my property description 1 \ No newline at end of file diff --git a/json/tests/testData/jsonSchema/documentation/withDefinition.html b/json/tests/testData/jsonSchema/documentation/withDefinition.html new file mode 100644 index 000000000000..d4bcb21909aa --- /dev/null +++ b/json/tests/testData/jsonSchema/documentation/withDefinition.html @@ -0,0 +1 @@ +Description found through definition \ No newline at end of file diff --git a/json/tests/testData/jsonSchema/documentation/withDefinition.json b/json/tests/testData/jsonSchema/documentation/withDefinition.json new file mode 100644 index 000000000000..67cd5bfb5990 --- /dev/null +++ b/json/tests/testData/jsonSchema/documentation/withDefinition.json @@ -0,0 +1,3 @@ +{ + "source": {} +} \ No newline at end of file diff --git a/json/tests/testData/jsonSchema/documentation/withDefinitionSchema.json b/json/tests/testData/jsonSchema/documentation/withDefinitionSchema.json new file mode 100644 index 000000000000..12ca74daad47 --- /dev/null +++ b/json/tests/testData/jsonSchema/documentation/withDefinitionSchema.json @@ -0,0 +1,12 @@ +{ + "definitions": { + "target": { + "description": "Description found through definition" + } + }, + "properties": { + "source": { + "$ref": "#/definitions/target" + } + } +} \ No newline at end of file diff --git a/json/tests/testData/jsonSchema/documentation/withDefinition_short.html b/json/tests/testData/jsonSchema/documentation/withDefinition_short.html new file mode 100644 index 000000000000..d4bcb21909aa --- /dev/null +++ b/json/tests/testData/jsonSchema/documentation/withDefinition_short.html @@ -0,0 +1 @@ +Description found through definition \ No newline at end of file diff --git a/json/tests/testData/jsonSchema/documentation/withTitleInDefinition.html b/json/tests/testData/jsonSchema/documentation/withTitleInDefinition.html new file mode 100644 index 000000000000..d4bcb21909aa --- /dev/null +++ b/json/tests/testData/jsonSchema/documentation/withTitleInDefinition.html @@ -0,0 +1 @@ +Description found through definition \ No newline at end of file diff --git a/json/tests/testData/jsonSchema/documentation/withTitleInDefinition.json b/json/tests/testData/jsonSchema/documentation/withTitleInDefinition.json new file mode 100644 index 000000000000..67cd5bfb5990 --- /dev/null +++ b/json/tests/testData/jsonSchema/documentation/withTitleInDefinition.json @@ -0,0 +1,3 @@ +{ + "source": {} +} \ No newline at end of file diff --git a/json/tests/testData/jsonSchema/documentation/withTitleInDefinitionSchema.json b/json/tests/testData/jsonSchema/documentation/withTitleInDefinitionSchema.json new file mode 100644 index 000000000000..7995bfeb9710 --- /dev/null +++ b/json/tests/testData/jsonSchema/documentation/withTitleInDefinitionSchema.json @@ -0,0 +1,13 @@ +{ + "definitions": { + "target": { + "title": "Title found through definition", + "description": "Description found through definition" + } + }, + "properties": { + "source": { + "$ref": "#/definitions/target" + } + } +} \ No newline at end of file diff --git a/json/tests/testData/jsonSchema/documentation/withTitleInDefinition_short.html b/json/tests/testData/jsonSchema/documentation/withTitleInDefinition_short.html new file mode 100644 index 000000000000..3fc51fb08d52 --- /dev/null +++ b/json/tests/testData/jsonSchema/documentation/withTitleInDefinition_short.html @@ -0,0 +1 @@ +Title found through definition \ No newline at end of file diff --git a/lib/asm-all.jar b/lib/asm-all.jar index a64a5929acec..6680557b43c8 100644 Binary files a/lib/asm-all.jar and b/lib/asm-all.jar differ diff --git a/lib/src/asm-src.zip b/lib/src/asm-src.zip index 427668e85d24..60b1005fcfb4 100644 Binary files a/lib/src/asm-src.zip and b/lib/src/asm-src.zip differ diff --git a/platform/annotations/internal/annotations-internal.iml b/platform/annotations/internal/annotations-internal.iml deleted file mode 100644 index c90834f2d607..000000000000 --- a/platform/annotations/internal/annotations-internal.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/TestingTasks.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/TestingTasks.groovy index 114eb6daadac..30a8df45a371 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/TestingTasks.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/TestingTasks.groovy @@ -17,6 +17,9 @@ package org.jetbrains.intellij.build import groovy.transform.CompileStatic import org.jetbrains.intellij.build.impl.TestingTasksImpl + +import java.util.function.Predicate + /** * @author nik */ @@ -26,7 +29,7 @@ abstract class TestingTasks { * @param defaultMainModule main module to be used instead of {@link TestingOptions#mainModule} if it isn't specified * @param excludedSourceDirectory if not {@code null} tests from modules which sources are located under this directory will be skipped */ - abstract void runTests(List additionalJvmOptions, String defaultMainModule, String excludedSourceDirectory) + abstract void runTests(List additionalJvmOptions, String defaultMainModule, Predicate rootExcludeCondition) static TestingTasks create(CompilationContext context, TestingOptions options = new TestingOptions()) { return new TestingTasksImpl(context, options) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy index 1ff5f96b5e7a..296b77d38c8b 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy @@ -111,7 +111,6 @@ class DistributionJARsBuilder { } withModule("util") withModule("util-rt", "util.jar") - withModule("annotations-internal", "util.jar") withModule("annotations") withModule("annotations-common", "annotations.jar") withModule("extensions") diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TestingTasksImpl.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TestingTasksImpl.groovy index c5ccb8cce72f..dbe1b35f56d4 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TestingTasksImpl.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TestingTasksImpl.groovy @@ -15,7 +15,6 @@ */ package org.jetbrains.intellij.build.impl -import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtilRt import groovy.transform.CompileDynamic import groovy.transform.CompileStatic @@ -28,6 +27,7 @@ import org.jetbrains.intellij.build.TestingTasks import org.jetbrains.jps.model.module.JpsModule import org.jetbrains.jps.util.JpsPathUtil +import java.util.function.Predicate /** * @author nik */ @@ -42,7 +42,7 @@ class TestingTasksImpl extends TestingTasks { } @Override - void runTests(List additionalJvmOptions, String defaultMainModule, String excludedSourceDirectory) { + void runTests(List additionalJvmOptions, String defaultMainModule, Predicate rootExcludeCondition) { def compilationTasks = CompilationTasks.create(context) if (options.mainModule != null) { compilationTasks.compileModules(["tests_bootstrap"], [options.mainModule]) @@ -108,11 +108,11 @@ class TestingTasksImpl extends TestingTasks { systemProperties[key.substring("pass.".length())] = value } } - - if (excludedSourceDirectory != null) { + + if (rootExcludeCondition != null) { List excludedModules = context.project.modules.findAll { List contentRoots = it.contentRootsList.urls - !contentRoots.isEmpty() && FileUtil.isAncestor(new File(excludedSourceDirectory), JpsPathUtil.urlToFile(contentRoots.first()), false) + !contentRoots.isEmpty() && rootExcludeCondition.test(JpsPathUtil.urlToFile(contentRoots.first())) } List excludedRoots = excludedModules.collectMany { [context.projectBuilder.moduleOutput(it), context.projectBuilder.moduleTestsOutput(it)] diff --git a/platform/configuration-store-impl/src/ModuleStateStorageManager.kt b/platform/configuration-store-impl/src/ModuleStateStorageManager.kt index 4ad610170681..ab0ef074018f 100644 --- a/platform/configuration-store-impl/src/ModuleStateStorageManager.kt +++ b/platform/configuration-store-impl/src/ModuleStateStorageManager.kt @@ -25,7 +25,6 @@ import com.intellij.openapi.project.ProjectBundle import com.intellij.openapi.project.isExternalStorageEnabled import com.intellij.openapi.vfs.newvfs.events.VFileEvent import com.intellij.util.LineSeparator -import com.intellij.util.io.systemIndependentPath import com.intellij.util.loadElement import org.jdom.Element import java.io.FileNotFoundException @@ -87,7 +86,7 @@ internal class ModuleStateStorageManager(macroSubstitutor: TrackingPathMacroSubs override fun createFileBasedStorage(path: String, collapsedPath: String, roamingType: RoamingType, rootTagName: String?): StateStorage = ModuleFileStorage(this, Paths.get(path), collapsedPath, rootTagName, roamingType, getMacroSubstitutor(collapsedPath), if (roamingType == RoamingType.DISABLED) null else compoundStreamProvider) - private class ModuleFileStorage(storageManager: StateStorageManagerImpl, + private class ModuleFileStorage(storageManager: ModuleStateStorageManager, file: Path, fileSpec: String, rootElementName: String?, @@ -100,8 +99,8 @@ internal class ModuleStateStorageManager(macroSubstitutor: TrackingPathMacroSubs val virtualFile = virtualFile if (virtualFile == null || !virtualFile.exists()) { // only on first load - if (storageDataRef.get() == null) { - throw FileNotFoundException(ProjectBundle.message("module.file.does.not.exist.error", file.systemIndependentPath)) + if (storageDataRef.get() == null && !storageManager.isExternalSystemStorageEnabled) { + throw FileNotFoundException(ProjectBundle.message("module.file.does.not.exist.error", file.toString())) } else { return null diff --git a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt index 288b7307a6ff..aa1e617e8547 100644 --- a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt +++ b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt @@ -318,7 +318,7 @@ open class StateStorageManagerImpl(private val rootTagName: String, } } - protected open val isExternalSystemStorageEnabled: Boolean + open val isExternalSystemStorageEnabled: Boolean get() = false protected open fun beforeElementSaved(element: Element) { diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileVisitor.java b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileVisitor.java index 686404162c83..2ac10887d7f5 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileVisitor.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileVisitor.java @@ -82,13 +82,13 @@ public abstract class VirtualFileVisitor { private boolean myFollowSymLinks = true; - private boolean mySkipRoot = false; + private boolean mySkipRoot; private int myDepthLimit = -1; private Map> myVisitedTargets; - private int myLevel = 0; - private Stack myValueStack = null; - private T myValue = null; + private int myLevel; + private Stack myValueStack; + private T myValue; protected VirtualFileVisitor(@NotNull Option... options) { for (Option option : options) { diff --git a/platform/core-api/src/com/intellij/util/AbstractQuery.java b/platform/core-api/src/com/intellij/util/AbstractQuery.java index 8f55163dcb6a..1589ceaae4e7 100644 --- a/platform/core-api/src/com/intellij/util/AbstractQuery.java +++ b/platform/core-api/src/com/intellij/util/AbstractQuery.java @@ -42,6 +42,7 @@ public abstract class AbstractQuery implements Query { return result; } + @NotNull @Override public Iterator iterator() { assertNotProcessing(); diff --git a/platform/core-api/src/com/intellij/util/ExecutorsQuery.java b/platform/core-api/src/com/intellij/util/ExecutorsQuery.java index fda929cc77ab..91ee040fb5d8 100644 --- a/platform/core-api/src/com/intellij/util/ExecutorsQuery.java +++ b/platform/core-api/src/com/intellij/util/ExecutorsQuery.java @@ -46,10 +46,7 @@ public final class ExecutorsQuery extends AbstractQuery extends Iterable { /** - * Get all of the results in the {@link java.util.Collection} + * Get all of the results in the {@link Collection} * @return results in a collection or empty collection if no results found. */ @NotNull diff --git a/platform/annotations/internal/src/org/jetbrains/annotations/SystemDependent.java b/platform/core-api/src/org/jetbrains/annotations/SystemDependent.java similarity index 100% rename from platform/annotations/internal/src/org/jetbrains/annotations/SystemDependent.java rename to platform/core-api/src/org/jetbrains/annotations/SystemDependent.java diff --git a/platform/annotations/internal/src/org/jetbrains/annotations/SystemIndependent.java b/platform/core-api/src/org/jetbrains/annotations/SystemIndependent.java similarity index 100% rename from platform/annotations/internal/src/org/jetbrains/annotations/SystemIndependent.java rename to platform/core-api/src/org/jetbrains/annotations/SystemIndependent.java diff --git a/platform/core-impl/src/com/intellij/openapi/progress/util/AbstractProgressIndicatorBase.java b/platform/core-impl/src/com/intellij/openapi/progress/util/AbstractProgressIndicatorBase.java index d74c7c2b50ba..10bca4f54152 100644 --- a/platform/core-impl/src/com/intellij/openapi/progress/util/AbstractProgressIndicatorBase.java +++ b/platform/core-impl/src/com/intellij/openapi/progress/util/AbstractProgressIndicatorBase.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.progress.util; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.TransactionGuard; @@ -25,13 +26,16 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.impl.CoreProgressManager; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.ui.mac.foundation.MacUtil; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.DoubleArrayList; import com.intellij.util.containers.Stack; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Set; @@ -127,15 +131,23 @@ public class AbstractProgressIndicatorBase extends UserDataHolderBase implements @Override public void checkCanceled() { if (isCanceled() && isCancelable()) { - throw new ProcessCanceledException(); + throw new ProcessCanceledException(getDisposeTrace()); } if (CoreProgressManager.runCheckCanceledHooks(this)) { if (isCanceled() && isCancelable()) { - throw new ProcessCanceledException(); + throw new ProcessCanceledException(getDisposeTrace()); } } } + @Nullable + private Throwable getDisposeTrace() { + if (this instanceof Disposable) { + return ObjectUtils.tryCast(Disposer.getTree().getDisposalInfo((Disposable)this), Throwable.class); + } + return null; + } + @Override public void setText(final String text) { myText = text; diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/impl/VirtualFileManagerImpl.java b/platform/core-impl/src/com/intellij/openapi/vfs/impl/VirtualFileManagerImpl.java index e05d8fbe0f09..38d8da323df6 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/impl/VirtualFileManagerImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/impl/VirtualFileManagerImpl.java @@ -85,8 +85,11 @@ public class VirtualFileManagerImpl extends VirtualFileManagerEx { public VirtualFileSystem getFileSystem(@Nullable String protocol) { if (protocol == null) return null; List systems = myCollector.forKey(protocol); - if (systems.isEmpty()) return null; - LOG.assertTrue(systems.size() == 1); + int size = systems.size(); + if (size == 0) return null; + if (size > 1) { + LOG.error(protocol + ": " + systems); + } return systems.get(0); } diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/ExternalSystemModulePropertyManager.kt b/platform/external-system-api/src/com/intellij/openapi/externalSystem/ExternalSystemModulePropertyManager.kt index 1d530169b7f2..20405cf42062 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/ExternalSystemModulePropertyManager.kt +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/ExternalSystemModulePropertyManager.kt @@ -15,95 +15,166 @@ */ package com.intellij.openapi.externalSystem +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.State import com.intellij.openapi.externalSystem.model.ProjectSystemId import com.intellij.openapi.externalSystem.model.project.ModuleData import com.intellij.openapi.externalSystem.model.project.ProjectData -import com.intellij.openapi.externalSystem.util.ExternalSystemConstants -import com.intellij.openapi.externalSystem.util.ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleServiceManager +import com.intellij.openapi.project.isExternalStorageEnabled import com.intellij.openapi.roots.ExternalProjectSystemRegistry - -private const val EXTERNAL_SYSTEM_MODULE_GROUP_KEY = "external.system.module.group" -private const val LINKED_PROJECT_PATH_KEY = "external.linked.project.path" -private const val LINKED_PROJECT_ID_KEY = "external.linked.project.id" -private const val EXTERNAL_SYSTEM_MODULE_TYPE_KEY = "external.system.module.type" -private const val EXTERNAL_SYSTEM_MODULE_VERSION_KEY = "external.system.module.version" -private const val ROOT_PROJECT_PATH_KEY = "external.root.project.path" +import com.intellij.openapi.roots.ProjectModelElement +import com.intellij.util.xmlb.annotations.Attribute +import com.intellij.util.xmlb.annotations.Transient +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty @Suppress("DEPRECATION") -class ExternalSystemModulePropertyManager(private val module: Module) { +@State(name = "ExternalSystem") +class ExternalSystemModulePropertyManager(module: Module) : PersistentStateComponent, ProjectModelElement { + override fun getExternalSource() = store.externalSystem?.let { ExternalProjectSystemRegistry.getInstance().getSourceById(it) } + + private var store = if (module.project.isExternalStorageEnabled) ExternalOptionStateComponent() else ExternalOptionStateModule(module) + + override fun getState() = store as? ExternalOptionStateComponent + + override fun loadState(state: ExternalOptionStateComponent) { + store = state + } + companion object { @JvmStatic fun getInstance(module: Module) = ModuleServiceManager.getService(module, ExternalSystemModulePropertyManager::class.java)!! } @Suppress("DEPRECATION") - fun getExternalSystemId() = module.getOptionValue(EXTERNAL_SYSTEM_ID_KEY) + fun getExternalSystemId() = store.externalSystem - fun getExternalModuleType() = module.getOptionValue(EXTERNAL_SYSTEM_MODULE_TYPE_KEY) + fun getExternalModuleType() = store.externalSystemModuleType - fun getExternalModuleVersion() = module.getOptionValue(EXTERNAL_SYSTEM_MODULE_VERSION_KEY) + fun getExternalModuleVersion() = store.externalSystemModuleVersion - fun getExternalModuleGroup() = module.getOptionValue(EXTERNAL_SYSTEM_MODULE_GROUP_KEY) + fun getExternalModuleGroup() = store.externalSystemModuleGroup - fun getLinkedProjectId() = module.getOptionValue(LINKED_PROJECT_ID_KEY) + fun getLinkedProjectId() = store.linkedProjectId - fun getRootProjectPath() = module.getOptionValue(ROOT_PROJECT_PATH_KEY) + fun getRootProjectPath() = store.rootProjectPath - fun getLinkedProjectPath() = module.getOptionValue(LINKED_PROJECT_PATH_KEY) + fun getLinkedProjectPath() = store.linkedProjectPath @Suppress("DEPRECATION") - fun isMavenized() = "true" == module.getOptionValue(ExternalProjectSystemRegistry.IS_MAVEN_MODULE_KEY) + fun isMavenized() = store.isMavenized @Suppress("DEPRECATION") fun setMavenized(mavenized: Boolean) { - module.setOption(ExternalProjectSystemRegistry.IS_MAVEN_MODULE_KEY, if (mavenized) "true" else null) - - if (!mavenized) { - return + if (mavenized) { + // clear external system API options + // see com.intellij.openapi.externalSystem.service.project.manage.ModuleDataService#setModuleOptions + unlinkExternalOptions() } - - // clear external system API options - // see com.intellij.openapi.externalSystem.service.project.manage.ModuleDataService#setModuleOptions - module.setOption(EXTERNAL_SYSTEM_ID_KEY, null) - module.setOption(LINKED_PROJECT_PATH_KEY, null) - module.setOption(ROOT_PROJECT_PATH_KEY, null) - module.setOption(EXTERNAL_SYSTEM_MODULE_GROUP_KEY, null) - module.setOption(EXTERNAL_SYSTEM_MODULE_VERSION_KEY, null) + // must be after unlinkExternalOptions + store.isMavenized = mavenized } fun unlinkExternalOptions() { - module.setOption(ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY, null) - module.setOption(LINKED_PROJECT_ID_KEY, null) - module.setOption(LINKED_PROJECT_PATH_KEY, null) - module.setOption(ROOT_PROJECT_PATH_KEY, null) - module.setOption(EXTERNAL_SYSTEM_MODULE_GROUP_KEY, null) - module.setOption(EXTERNAL_SYSTEM_MODULE_VERSION_KEY, null) + store.externalSystem = null + store.linkedProjectId = null + store.linkedProjectPath = null + store.rootProjectPath = null + store.externalSystemModuleGroup = null + store.externalSystemModuleVersion = null } fun setExternalOptions(id: ProjectSystemId, moduleData: ModuleData, projectData: ProjectData?) { - module.setOption(ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY, id.toString()) - module.setOption(LINKED_PROJECT_ID_KEY, moduleData.id) - module.setOption(LINKED_PROJECT_PATH_KEY, moduleData.linkedExternalProjectPath) - module.setOption(ROOT_PROJECT_PATH_KEY, projectData?.linkedExternalProjectPath ?: "") + // clear maven option, must be first + store.isMavenized = false - module.setOption(EXTERNAL_SYSTEM_MODULE_GROUP_KEY, moduleData.group) - module.setOption(EXTERNAL_SYSTEM_MODULE_VERSION_KEY, moduleData.version) + store.externalSystem = id.toString() + store.linkedProjectId = moduleData.id + store.linkedProjectPath = moduleData.linkedExternalProjectPath + store.rootProjectPath = projectData?.linkedExternalProjectPath ?: "" - // clear maven option - module.setOption(ExternalProjectSystemRegistry.IS_MAVEN_MODULE_KEY, null) + store.externalSystemModuleGroup = moduleData.group + store.externalSystemModuleVersion = moduleData.version } fun setExternalId(id: ProjectSystemId) { - module.setOption(EXTERNAL_SYSTEM_ID_KEY, id.id) + store.externalSystem = id.id } fun setExternalModuleType(type: String?) { - module.setOption(EXTERNAL_SYSTEM_MODULE_TYPE_KEY, type) + store.externalSystemModuleType = type } fun setLinkedProjectId(projectId: String) { - module.setOption(LINKED_PROJECT_ID_KEY, projectId) + store.linkedProjectId = projectId } +} + +private interface ExternalOptionState { + var externalSystem: String? + var externalSystemModuleVersion: String? + + var linkedProjectPath: String? + var linkedProjectId: String? + var rootProjectPath: String? + + var externalSystemModuleGroup: String? + var externalSystemModuleType: String? + + var isMavenized: Boolean +} + +@Suppress("DEPRECATION") +private class ModuleOptionDelegate(private val key: String) : ReadWriteProperty { + override operator fun getValue(thisRef: ExternalOptionStateModule, property: KProperty<*>) = thisRef.module.getOptionValue(key) + + override operator fun setValue(thisRef: ExternalOptionStateModule, property: KProperty<*>, value: String?) { + thisRef.module.setOption(key, value) + } +} + +@Suppress("DEPRECATION") +private class ExternalOptionStateModule(internal val module: Module) : ExternalOptionState { + override var externalSystem by ModuleOptionDelegate(ExternalProjectSystemRegistry.EXTERNAL_SYSTEM_ID_KEY) + override var externalSystemModuleVersion by ModuleOptionDelegate("external.system.module.version") + override var externalSystemModuleGroup by ModuleOptionDelegate("external.system.module.group") + override var externalSystemModuleType by ModuleOptionDelegate("external.system.module.type") + + override var linkedProjectPath by ModuleOptionDelegate("external.linked.project.path") + override var linkedProjectId by ModuleOptionDelegate("external.linked.project.id") + + override var rootProjectPath by ModuleOptionDelegate("external.root.project.path") + + override var isMavenized: Boolean + get() = "true" == module.getOptionValue(ExternalProjectSystemRegistry.IS_MAVEN_MODULE_KEY) + set(value) { + module.setOption(ExternalProjectSystemRegistry.IS_MAVEN_MODULE_KEY, if (value) "true" else null) + } +} + +class ExternalOptionStateComponent : ExternalOptionState { + @get:Attribute + override var externalSystem: String? = null + @get:Attribute + override var externalSystemModuleVersion: String? = null + @get:Attribute + override var externalSystemModuleGroup: String? = null + @get:Attribute + override var externalSystemModuleType: String? = null + + @get:Attribute + override var linkedProjectPath: String? = null + @get:Attribute + override var linkedProjectId: String? = null + @get:Attribute + override var rootProjectPath: String? = null + + @get:Transient + override var isMavenized: Boolean + get() = externalSystem == ExternalProjectSystemRegistry.MAVEN_EXTERNAL_SOURCE_ID + set(value) { + externalSystem = if (value) ExternalProjectSystemRegistry.MAVEN_EXTERNAL_SOURCE_ID else null + } } \ No newline at end of file diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStorage.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStorage.kt index f87802fe7072..e4cb512a9f3c 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStorage.kt +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStorage.kt @@ -22,7 +22,6 @@ import com.intellij.configurationStore.XmlElementStorage import com.intellij.openapi.components.RoamingType import com.intellij.openapi.components.StateSplitterEx import com.intellij.openapi.components.StoragePathMacros -import com.intellij.openapi.externalSystem.ExternalSystemModulePropertyManager import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project import com.intellij.openapi.util.JDOMUtil @@ -36,16 +35,11 @@ internal class ExternalModuleStorage(private val module: Module, storageManager: override fun createSaveSession(states: StateMap) = object : XmlElementStorageSaveSession(states, this) { override fun saveLocally(element: Element?) { // our customizeStorageSpecs on write will not return our storage for not applicable module, so, we don't need to check it here - var name = module.name - if (ExternalSystemModulePropertyManager.getInstance(module).isMavenized()) { - // to distinguish because one project can contain modules from different external systems - name += "@maven" - } if (element == null) { - manager.moduleStorage.remove(name) + manager.moduleStorage.remove(module.name) } else { - manager.moduleStorage.write(name, element) + manager.moduleStorage.write(module.name, element) } } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/model/internal/InternalExternalProjectInfo.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/model/internal/InternalExternalProjectInfo.java index 3d2a1cf3f87c..e7f7ca9b23b7 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/model/internal/InternalExternalProjectInfo.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/model/internal/InternalExternalProjectInfo.java @@ -61,6 +61,11 @@ public class InternalExternalProjectInfo implements ExternalProjectInfo, Seriali return myExternalProjectPath; } + @Nullable + public String getNullSafeExternalProjectPath() { + return myExternalProjectPath; + } + @Override @Nullable public DataNode getExternalProjectStructure() { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsDataStorage.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsDataStorage.java index 97bcc853f59b..17456ace75f4 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsDataStorage.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsDataStorage.java @@ -104,7 +104,10 @@ public class ExternalProjectsDataStorage implements SettingsSavingComponent, Per } } else { - markDirty(projectInfo.getExternalProjectPath()); + String projectPath = projectInfo.getNullSafeExternalProjectPath(); + if (projectPath != null) { + markDirty(projectPath); + } } } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManagerImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManagerImpl.java index bb768b947438..993995985eb7 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManagerImpl.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManagerImpl.java @@ -18,6 +18,7 @@ package com.intellij.openapi.externalSystem.service.project.manage; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.*; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.importing.ImportSpec; import com.intellij.openapi.externalSystem.model.DataNode; @@ -33,8 +34,12 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; import com.intellij.openapi.externalSystem.view.ExternalProjectsView; import com.intellij.openapi.externalSystem.view.ExternalProjectsViewImpl; import com.intellij.openapi.externalSystem.view.ExternalProjectsViewState; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectFileStoreOptionManager; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.impl.ModuleRootManagerImpl; import com.intellij.openapi.util.Disposer; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; @@ -57,6 +62,8 @@ import static com.intellij.openapi.externalSystem.model.ProjectKeys.TASK; */ @State(name = "ExternalProjectsManager", storages = {@Storage(StoragePathMacros.WORKSPACE_FILE)}) public class ExternalProjectsManagerImpl implements ExternalProjectsManager, PersistentStateComponent, Disposable, ProjectFileStoreOptionManager { + private static final Logger LOG = Logger.getInstance(ExternalProjectsManager.class); + private final AtomicBoolean isInitializationFinished = new AtomicBoolean(); private final AtomicBoolean isInitializationStarted = new AtomicBoolean(); private final CompositeRunnable myPostInitializationActivities = new CompositeRunnable(); @@ -91,6 +98,17 @@ public class ExternalProjectsManagerImpl implements ExternalProjectsManager, Per public void setStoreExternally(boolean value) { myState.storeExternally = value; + // force re-save + try { + for (Module module : ModuleManager.getInstance(myProject).getModules()) { + if (!module.isDisposed()) { + ((ModuleRootManagerImpl)ModuleRootManager.getInstance(module)).stateChanged(); + } + } + } + catch (Exception e) { + LOG.warn(e); + } } @NotNull diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsState.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsState.java index c1ef849a637e..867f93f6c67a 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsState.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsState.java @@ -64,6 +64,7 @@ public class ExternalProjectsState { return new TaskActivationState(); } + @NotNull @Override protected Map createMap() { return new LinkedHashMap<>(); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalProjectSettingsControl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalProjectSettingsControl.java index b87b035e3615..b02342dd32bb 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalProjectSettingsControl.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalProjectSettingsControl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -80,6 +80,7 @@ public abstract class AbstractExternalProjectSettingsControl settings = ContainerUtilRt.newArrayList(s.getLinkedProjectsSettings()); myProjectsList.setVisibleRowCount(Math.max(3, Math.min(5, settings.size()))); - ContainerUtil.sort(settings, - (s1, s2) -> getProjectName(s1.getExternalProjectPath()).compareTo(getProjectName(s2.getExternalProjectPath()))); + ContainerUtil.sort(settings, Comparator.comparing(s2 -> getProjectName(s2.getExternalProjectPath()))); myProjectSettingsControls.clear(); for (ProjectSettings setting : settings) { diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStorageTest.kt b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStorageTest.kt index 4d322f3339ff..b7986315ead1 100644 --- a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStorageTest.kt +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/configurationStore/ExternalSystemStorageTest.kt @@ -16,12 +16,15 @@ package com.intellij.openapi.externalSystem.configurationStore import com.intellij.configurationStore.ESCAPED_MODULE_DIR -import com.intellij.configurationStore.IS_EXTERNAL_STORAGE_ENABLED import com.intellij.configurationStore.createModule import com.intellij.configurationStore.useAndDispose import com.intellij.openapi.externalSystem.ExternalSystemModulePropertyManager import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsDataStorage +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.roots.impl.ModuleRootManagerImpl import com.intellij.testFramework.* import com.intellij.testFramework.assertions.Assertions.assertThat import com.intellij.util.io.delete @@ -47,7 +50,7 @@ class ExternalSystemStorageTest { @Suppress("unused") @JvmField @Rule - val ruleChain = RuleChain(tempDirManager, EdtRule(), ActiveStoreRule(projectRule), DisposeModulesRule(projectRule), ExternalStorageRule()) + val ruleChain = RuleChain(tempDirManager, EdtRule(), ActiveStoreRule(projectRule), DisposeModulesRule(projectRule), ExternalStorageRule(projectRule.project)) @Test fun `must be empty if external system storage`() { @@ -74,16 +77,19 @@ class ExternalSystemStorageTest { """) ExternalSystemModulePropertyManager.getInstance(this).setMavenized(true) + // force re-save: this call not in the setMavenized because ExternalSystemModulePropertyManager in the API (since in production we have the only usage, it is ok for now) + (ModuleRootManager.getInstance(this) as ModuleRootManagerImpl).stateChanged() assertThat(cacheDir).doesNotExist() saveStore() assertThat(cacheDir).isDirectory assertThat(moduleFile).isEqualTo(""" - """) + """) - assertThat(cacheDir.resolve("test@maven.xml")).isEqualTo(""" + assertThat(cacheDir.resolve("test.xml")).isEqualTo(""" + @@ -94,15 +100,16 @@ class ExternalSystemStorageTest { } } -private class ExternalStorageRule : TestRule { +private class ExternalStorageRule(private val project: Project) : TestRule { override fun apply(base: Statement, description: Description): Statement { return statement { + val manager = ExternalProjectsManagerImpl.getInstance(project) try { - IS_EXTERNAL_STORAGE_ENABLED = true + manager.setStoreExternally(true) base.evaluate() } finally { - IS_EXTERNAL_STORAGE_ENABLED = false + manager.setStoreExternally(false) } } } diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/file/impl/ResolveScopeManagerImpl.java b/platform/indexing-impl/src/com/intellij/psi/impl/file/impl/ResolveScopeManagerImpl.java index 0b1d597c67a8..d4e1ac91aa26 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/file/impl/ResolveScopeManagerImpl.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/file/impl/ResolveScopeManagerImpl.java @@ -49,6 +49,7 @@ public class ResolveScopeManagerImpl extends ResolveScopeManager { private final Map myDefaultResolveScopesCache = new FactoryMap() { + @NotNull @Override protected Map createMap() { return ContainerUtil.createConcurrentWeakKeySoftValueMap(); diff --git a/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java b/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java index 827cce9db74d..1052ba973f20 100644 --- a/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java +++ b/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java @@ -39,13 +39,12 @@ import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; import java.awt.*; import java.util.Comparator; public class PsiUtilBase extends PsiUtilCore implements PsiEditorUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.util.PsiUtilBase"); - public static final Comparator LANGUAGE_COMPARATOR = (o1, o2) -> o1.getID().compareTo(o2.getID()); + public static final Comparator LANGUAGE_COMPARATOR = Comparator.comparing(Language::getID); public static boolean isUnderPsiRoot(PsiFile root, PsiElement element) { PsiFile containingFile = element.getContainingFile(); @@ -74,10 +73,7 @@ public class PsiUtilBase extends PsiUtilCore implements PsiEditorUtil { Language lang = findLanguageFromElement(elt); if (caret.hasSelection()) { - final Language rangeLanguage = evaluateLanguageInRange(caret.getSelectionStart(), caret.getSelectionEnd(), file); - if (rangeLanguage == null) return file.getLanguage(); - - lang = rangeLanguage; + lang = evaluateLanguageInRange(caret.getSelectionStart(), caret.getSelectionEnd(), file); } return narrowLanguage(lang, file.getLanguage()); @@ -152,8 +148,8 @@ public class PsiUtilBase extends PsiUtilCore implements PsiEditorUtil { return narrowLanguage(lang, file.getLanguage()); } - @Nullable - public static Language evaluateLanguageInRange(final int start, final int end, @NotNull PsiFile file) { + @NotNull + private static Language evaluateLanguageInRange(final int start, final int end, @NotNull PsiFile file) { PsiElement elt = getElementAtOffset(file, start); TextRange selectionRange = new TextRange(start, end); @@ -195,7 +191,7 @@ public class PsiUtilBase extends PsiUtilCore implements PsiEditorUtil { * *

* Please don't use this method for finding an editor for quick fix. - * @see {@link com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement} + * @see com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement * * @param element target element * @return editor that works with a given element if the one is found; {@code null} otherwise @@ -221,17 +217,15 @@ public class PsiUtilBase extends PsiUtilCore implements PsiEditorUtil { } } } - if (SwingUtilities.isEventDispatchThread()) { - // We assume that data context from focus-based retrieval should success if performed from EDT. - AsyncResult asyncResult = DataManager.getInstance().getDataContextFromFocus(); - if (asyncResult.isDone()) { - Editor editor = CommonDataKeys.EDITOR.getData(asyncResult.getResult()); - if (editor != null) { - Document cachedDocument = PsiDocumentManager.getInstance(project).getCachedDocument(psiFile); - // Ensure that target editor is found by checking its document against the one from given PSI element. - if (cachedDocument == editor.getDocument()) { - return editor; - } + // We assume that data context from focus-based retrieval should success if performed from EDT. + AsyncResult asyncResult = DataManager.getInstance().getDataContextFromFocus(); + if (asyncResult.isDone()) { + Editor editor = CommonDataKeys.EDITOR.getData(asyncResult.getResult()); + if (editor != null) { + Document cachedDocument = PsiDocumentManager.getInstance(project).getCachedDocument(psiFile); + // Ensure that target editor is found by checking its document against the one from given PSI element. + if (cachedDocument == editor.getDocument()) { + return editor; } } } diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/fonts/AppEditorFontConfigurable.java b/platform/lang-impl/src/com/intellij/application/options/editor/fonts/AppEditorFontConfigurable.java index 399cc8f7212f..2ebc48203cde 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/fonts/AppEditorFontConfigurable.java +++ b/platform/lang-impl/src/com/intellij/application/options/editor/fonts/AppEditorFontConfigurable.java @@ -21,6 +21,7 @@ import com.intellij.openapi.editor.colors.EditorFontCache; import com.intellij.openapi.editor.colors.FontPreferences; import com.intellij.openapi.editor.colors.impl.AppEditorFontOptions; import com.intellij.openapi.editor.colors.impl.EditorColorsManagerImpl; +import com.intellij.openapi.options.Configurable.NoScroll; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.util.Disposer; @@ -31,7 +32,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; -public class AppEditorFontConfigurable implements SearchableConfigurable { +public class AppEditorFontConfigurable implements SearchableConfigurable, NoScroll { public static final String ID = "editor.preferences.fonts.default"; private LazyInstance myFontPanelInstance = new LazyInstance() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java index 8ffd4276239e..7b7bc8753c1e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java @@ -29,8 +29,8 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.SmartPointerManager; @@ -62,6 +62,7 @@ class UpdateFoldRegionsOperation implements Runnable { private final ApplyDefaultStateMode myApplyDefaultState; private final FoldingMap myElementsToFoldMap = new FoldingMap(); private final Set myRegionInfos = new LinkedHashSet<>(); + private final MultiMap myGroupedRegionInfos = new MultiMap<>(); private final boolean myKeepCollapsedRegions; private final boolean myForInjected; @@ -81,6 +82,8 @@ class UpdateFoldRegionsOperation implements Runnable { for (FoldingUpdate.RegionInfo regionInfo : elementsToFold) { myElementsToFoldMap.putValue(regionInfo.element, regionInfo); myRegionInfos.add(regionInfo); + FoldingGroup group = regionInfo.descriptor.getGroup(); + if (group != null) myGroupedRegionInfos.putValue(group, regionInfo); } } @@ -192,62 +195,60 @@ class UpdateFoldRegionsOperation implements Runnable { @NotNull FoldingModelEx foldingModel, @NotNull Map rangeToExpandStatusMap) { List toRemove = new ArrayList<>(); - InjectedLanguageManager injectedManager = InjectedLanguageManager.getInstance(myProject); + Ref infoRef = Ref.create(); + Set processedGroups = new HashSet<>(); + List matchedInfos = new ArrayList<>(); for (FoldRegion region : foldingModel.getAllFoldRegions()) { - boolean forceKeepRegion = myKeepCollapsedRegions && region.isValid() && !region.isExpanded() && - !regionOrGroupCanBeRemovedWhenCollapsed(region); - Boolean storedCollapsedByDefault = region.getUserData(COLLAPSED_BY_DEFAULT); - PsiElement element = info.getPsiElement(region); - if (element != null) { - PsiFile containingFile = element.getContainingFile(); - boolean isInjected = injectedManager.isInjectedFragment(containingFile); - if (isInjected != myForInjected) continue; + FoldingGroup group = region.getGroup(); + if (group != null && !processedGroups.add(group)) continue; + + List regionsToProcess = group == null ? Collections.singletonList(region) : foldingModel.getGroupedRegions(group); + matchedInfos.clear(); + boolean shouldRemove = false; + for (FoldRegion regionToProcess : regionsToProcess) { + if (shouldRemoveRegion(regionToProcess, info, rangeToExpandStatusMap, infoRef)) { + shouldRemove = true; + } + FoldingUpdate.RegionInfo regionInfo = infoRef.get(); + matchedInfos.add(regionInfo); } - final Collection regionInfos; - if (element != null && !(regionInfos = myElementsToFoldMap.get(element)).isEmpty()) { - boolean matchingDescriptorFound = false; - FoldingUpdate.RegionInfo[] array = regionInfos.toArray(new FoldingUpdate.RegionInfo[regionInfos.size()]); - for (FoldingUpdate.RegionInfo regionInfo : array) { - FoldingDescriptor descriptor = regionInfo.descriptor; - TextRange range = descriptor.getRange(); - if (TextRange.areSegmentsEqual(region, range)) { - matchingDescriptorFound = true; - if (!forceKeepRegion && (!region.isValid() || - region.getGroup() != null || - descriptor.getGroup() != null || - !region.getPlaceholderText().equals(descriptor.getPlaceholderText()) || - range.getLength() < 2) - ) { - rangeToExpandStatusMap.put(range, region.isExpanded()); - toRemove.add(region); - break; - } - else if (storedCollapsedByDefault != null && storedCollapsedByDefault != regionInfo.collapsedByDefault) { - rangeToExpandStatusMap.put(range, !regionInfo.collapsedByDefault); - toRemove.add(region); - break; - } - else { - myElementsToFoldMap.remove(element, regionInfo); - myRegionInfos.remove(regionInfo); - } + if (!shouldRemove && group != null) { + FoldingGroup requestedGroup = null; + for (FoldingUpdate.RegionInfo matchedInfo : matchedInfos) { + if (matchedInfo == null) { + shouldRemove = true; + break; + } + FoldingGroup g = matchedInfo.descriptor.getGroup(); + if (g == null) { + shouldRemove = true; + break; + } + if (requestedGroup == null) { + requestedGroup = g; + } + else if (!requestedGroup.equals(g)) { + shouldRemove = true; + break; } } - if (!matchingDescriptorFound && !forceKeepRegion) { - if (Registry.is("editor.durable.folding.state")) { - for (FoldingUpdate.RegionInfo regionInfo : regionInfos) { - rangeToExpandStatusMap.put(regionInfo.descriptor.getRange(), region.isExpanded()); - } - } - toRemove.add(region); + if (myGroupedRegionInfos.get(requestedGroup).size() != matchedInfos.size()) { + shouldRemove = true; + } + } + if (shouldRemove) { + for (FoldRegion r : regionsToProcess) { + rangeToExpandStatusMap.putIfAbsent(TextRange.create(r), r.isExpanded()); } + toRemove.addAll(regionsToProcess); } - else if (region.isValid() && info.isLightRegion(region)) { - boolean isExpanded = region.isExpanded(); - rangeToExpandStatusMap.put(TextRange.create(region), isExpanded); - } - else if (!forceKeepRegion) { - toRemove.add(region); + else { + for (FoldingUpdate.RegionInfo matchedInfo : matchedInfos) { + if (matchedInfo != null) { + myElementsToFoldMap.remove(matchedInfo.element, matchedInfo); + myRegionInfos.remove(matchedInfo); + } + } } } @@ -257,6 +258,54 @@ class UpdateFoldRegionsOperation implements Runnable { } } + private boolean shouldRemoveRegion(FoldRegion region, EditorFoldingInfo info, + Map rangeToExpandStatusMap, Ref matchingInfo) { + matchingInfo.set(null); + PsiElement element = info.getPsiElement(region); + if (element != null) { + PsiFile containingFile = element.getContainingFile(); + boolean isInjected = InjectedLanguageManager.getInstance(myProject).isInjectedFragment(containingFile); + if (isInjected != myForInjected) return false; + } + boolean forceKeepRegion = myKeepCollapsedRegions && region.isValid() && !region.isExpanded() && + !regionOrGroupCanBeRemovedWhenCollapsed(region); + Boolean storedCollapsedByDefault = region.getUserData(COLLAPSED_BY_DEFAULT); + final Collection regionInfos; + if (element != null && !(regionInfos = myElementsToFoldMap.get(element)).isEmpty()) { + FoldingUpdate.RegionInfo[] array = regionInfos.toArray(new FoldingUpdate.RegionInfo[regionInfos.size()]); + for (FoldingUpdate.RegionInfo regionInfo : array) { + FoldingDescriptor descriptor = regionInfo.descriptor; + TextRange range = descriptor.getRange(); + if (TextRange.areSegmentsEqual(region, range)) { + if (!forceKeepRegion && (!region.isValid() || + !region.getPlaceholderText().equals(descriptor.getPlaceholderText()) || + range.getLength() < 2) + ) { + return true; + } + else if (storedCollapsedByDefault != null && storedCollapsedByDefault != regionInfo.collapsedByDefault) { + rangeToExpandStatusMap.put(range, !regionInfo.collapsedByDefault); + return true; + } + else { + matchingInfo.set(regionInfo); + return false; + } + } + } + if (!forceKeepRegion) { + for (FoldingUpdate.RegionInfo regionInfo : regionInfos) { + rangeToExpandStatusMap.put(regionInfo.descriptor.getRange(), region.isExpanded()); + } + return true; + } + } + else if (!forceKeepRegion && !(region.isValid() && info.isLightRegion(region))) { + return true; + } + return false; + } + private boolean regionOrGroupCanBeRemovedWhenCollapsed(FoldRegion region) { FoldingGroup group = region.getGroup(); List affectedRegions = group != null && myEditor instanceof EditorEx diff --git a/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java b/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java index 90ada3845f1c..750c51f9d1df 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java +++ b/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java @@ -82,6 +82,7 @@ public class ConsoleHistoryController { /** @noinspection MismatchedQueryAndUpdateOfCollection*/ private final static FactoryMap ourModels = new FactoryMap() { + @NotNull @Override protected Map createMap() { return ContainerUtil.createConcurrentWeakValueMap(); diff --git a/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerContributor.java b/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerContributor.java index c85a98b1ec94..ba804cfbe6bd 100644 --- a/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerContributor.java +++ b/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerContributor.java @@ -15,10 +15,15 @@ */ package com.intellij.execution.lineMarker; +import com.intellij.execution.TestStateStorage; +import com.intellij.execution.testframework.TestIconMapper; +import com.intellij.execution.testframework.sm.runner.states.TestStateInfo; +import com.intellij.icons.AllIcons; import com.intellij.ide.DataManager; import com.intellij.lang.LanguageExtension; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.impl.SimpleDataContext; +import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -74,4 +79,22 @@ public abstract class RunLineMarkerContributor { return presentation.isEnabled() && presentation.isVisible() ? presentation.getText() : null; } + protected static Icon getTestStateIcon(String url, Project project, boolean isClass) { + TestStateStorage.Record state = TestStateStorage.getInstance(project).getState(url); + if (state != null) { + TestStateInfo.Magnitude magnitude = TestIconMapper.getMagnitude(state.magnitude); + if (magnitude != null) { + switch (magnitude) { + case ERROR_INDEX: + case FAILED_INDEX: + return AllIcons.RunConfigurations.TestState.Red2; + case PASSED_INDEX: + case COMPLETE_INDEX: + return AllIcons.RunConfigurations.TestState.Green2; + default: + } + } + } + return isClass ? AllIcons.RunConfigurations.TestState.Run_run : AllIcons.RunConfigurations.TestState.Run; + } } diff --git a/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java b/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java index c0fe923f9e4c..e0ef589cd2ef 100644 --- a/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java +++ b/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java @@ -58,7 +58,6 @@ import com.intellij.usages.rules.UsageInFile; import com.intellij.util.AdapterProcessor; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.*; @@ -491,8 +490,8 @@ public class ReplaceInProjectManager { return true; } - private void replaceUsagesUnderCommand(@NotNull final ReplaceContext replaceContext, @Nullable final Set usagesSet) { - if (usagesSet == null) { + private void replaceUsagesUnderCommand(@NotNull final ReplaceContext replaceContext, @NotNull final Set usagesSet) { + if (usagesSet.isEmpty()) { return; } diff --git a/platform/lang-impl/src/com/intellij/ide/hierarchy/ExporterToTextFileHierarchy.java b/platform/lang-impl/src/com/intellij/ide/hierarchy/ExporterToTextFileHierarchy.java index 85a50b10e060..5095aa645704 100644 --- a/platform/lang-impl/src/com/intellij/ide/hierarchy/ExporterToTextFileHierarchy.java +++ b/platform/lang-impl/src/com/intellij/ide/hierarchy/ExporterToTextFileHierarchy.java @@ -58,13 +58,12 @@ class ExporterToTextFileHierarchy implements ExporterToTextFile { } private void appendNode(StringBuilder buf, DefaultMutableTreeNode node, String lineSeparator, String indent) { - buf.append(indent); final String childIndent; if (node.getParent() != null) { childIndent = indent + " "; final HierarchyNodeDescriptor descriptor = myHierarchyBrowserBase.getDescriptor(node); if (descriptor != null) { - buf.append(descriptor.getHighlightedText().getText()).append(lineSeparator); + buf.append(indent).append(descriptor.getHighlightedText().getText()).append(lineSeparator); } } else { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index 5ccdd2e85c2b..5c678abaef17 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -106,6 +106,8 @@ import java.awt.*; import java.util.*; import java.util.List; +import static com.intellij.ide.projectView.impl.StatisticsKt.triggerProjectViewPane; + @State(name = "ProjectView", storages = @Storage(StoragePathMacros.WORKSPACE_FILE)) public class ProjectViewImpl extends ProjectView implements PersistentStateComponent, Disposable, QuickActionProvider, BusyObject { private static final Logger LOG = Logger.getInstance("#com.intellij.ide.projectView.impl.ProjectViewImpl"); @@ -546,7 +548,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo @Override public void selectionChanged(ContentManagerEvent event) { if (event.getOperation() == ContentManagerEvent.ContentOperation.add) { - viewSelectionChanged(); + viewSelectionChanged(true); } } }); @@ -575,6 +577,10 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo } private boolean viewSelectionChanged() { + return viewSelectionChanged(false); + } + + private boolean viewSelectionChanged(boolean fromContentManager) { Content content = getContentManager().getSelectedContent(); if (content == null) return false; final String id = content.getUserData(ID_KEY); @@ -584,6 +590,9 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo if (newPane == null) return false; newPane.setSubId(subId); showPane(newPane); + if (fromContentManager) { + triggerProjectViewPane(myCurrentViewId, myCurrentViewSubId); + } ProjectViewSelectInTarget target = getProjectViewSelectInTarget(newPane); if (target != null) target.setSubId(subId); if (isAutoscrollFromSource(id)) { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/statistics.kt b/platform/lang-impl/src/com/intellij/ide/projectView/impl/statistics.kt new file mode 100644 index 000000000000..bb42b146c88b --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/statistics.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.projectView.impl + +import com.intellij.internal.statistic.UsageTrigger +import com.intellij.internal.statistic.beans.ConvertUsagesUtil.ensureProperKey + +private val prefix = "project.view.pane" + +internal fun triggerProjectViewPane(id: String?, subId: String?) { + if (id == null) return + val featureString = if (subId == null) "$prefix.$id" else "$prefix.$id.$subId" + val key = ensureProperKey(featureString) + UsageTrigger.trigger(key) +} diff --git a/platform/lang-impl/src/com/intellij/mock/MockFileManager.java b/platform/lang-impl/src/com/intellij/mock/MockFileManager.java index 04848c280611..f293f7d2f160 100644 --- a/platform/lang-impl/src/com/intellij/mock/MockFileManager.java +++ b/platform/lang-impl/src/com/intellij/mock/MockFileManager.java @@ -39,6 +39,7 @@ public class MockFileManager implements FileManager { // in mock tests it's LightVirtualFile, they're only alive when they're referenced, // and there can not be several instances representing the same file private final FactoryMap myViewProviders = new ConcurrentWeakFactoryMap() { + @NotNull @Override protected Map createMap() { return ContainerUtil.createConcurrentWeakKeyWeakValueMap(); diff --git a/java/java-impl/src/com/intellij/refactoring/actions/RenameFileAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/RenameFileAction.java similarity index 86% rename from java/java-impl/src/com/intellij/refactoring/actions/RenameFileAction.java rename to platform/lang-impl/src/com/intellij/refactoring/actions/RenameFileAction.java index 56d07e1985a5..c7c04f4d0ae9 100644 --- a/java/java-impl/src/com/intellij/refactoring/actions/RenameFileAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/RenameFileAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,9 +19,9 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiClassOwner; import com.intellij.psi.PsiFile; import com.intellij.refactoring.rename.PsiElementRenameHandler; +import org.jetbrains.annotations.NotNull; /** * @author ven @@ -48,8 +48,8 @@ public class RenameFileAction extends AnAction implements DumbAware { PsiFile file = e.getData(CommonDataKeys.PSI_FILE); Presentation presentation = e.getPresentation(); String place = e.getPlace(); - boolean enabled = file != null && - (file instanceof PsiClassOwner || !ActionPlaces.PROJECT_VIEW_POPUP.equals(place)) && + boolean enabled = file != null && + (enabledInProjectView(file) || !ActionPlaces.PROJECT_VIEW_POPUP.equals(place)) && place != ActionPlaces.EDITOR_POPUP && e.getData(CommonDataKeys.PROJECT) != null; presentation.setEnabled(enabled); presentation.setVisible(enabled); @@ -58,4 +58,8 @@ public class RenameFileAction extends AnAction implements DumbAware { presentation.setDescription("Rename selected file"); } } + + protected boolean enabledInProjectView(@NotNull PsiFile file) { + return true; + } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 69ab2b03a203..32673635d193 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -318,6 +318,12 @@ public class FileBasedIndexImpl extends FileBasedIndex implements BaseComponent, started = System.nanoTime(); myStateFuture = IndexInfrastructure.submitGenesisTask(new FileIndexDataInitialization(extensions)); + IndexInfrastructure.submitGenesisTask(() -> { + if (!myShutdownPerformed.get()) { + myChangedFilesCollector.ensureUpToDateAsync(); + } + return null; + }); LOG.info("Index scheduled:" + (System.nanoTime() - started) / 1000000); if (!IndexInfrastructure.ourDoAsyncIndicesInitialization) { waitUntilIndicesAreInitialized(); @@ -2381,8 +2387,6 @@ public class FileBasedIndexImpl extends FileBasedIndex implements BaseComponent, } }); myInitialized = true; // this will ensure that all changes to component's state will be visible to other threads - - myChangedFilesCollector.ensureUpToDateAsync(); } } } diff --git a/platform/platform-api/src/com/intellij/ui/UI.java b/platform/platform-api/src/com/intellij/ui/UI.java index 1aaba6a8b35a..731022af83df 100644 --- a/platform/platform-api/src/com/intellij/ui/UI.java +++ b/platform/platform-api/src/com/intellij/ui/UI.java @@ -40,6 +40,7 @@ public class UI { ourColors.put("panel.custom.background", new Color(250, 249, 245)); ourColors.put("link.foreground", new Color(82, 99, 155)); + ourColors.put("link.hover.foreground", new JBColor(new Color(82, 99, 155), new Color(82, 99, 155))); ourColors.put("link.pressed.foreground", new JBColor(new Color(240, 0, 0), new Color(186, 111, 37))); ourColors.put("link.visited.foreground", new JBColor(new Color(128, 0, 128), new Color(151, 118, 169))); @@ -73,7 +74,7 @@ public class UI { } public static Color getColor(@NonNls String id) { - if (UIUtil.isUnderDarcula()) { + if (UIUtil.isUnderDarcula() || UIUtil.isUnderWin10LookAndFeel()) { final Color color = UIManager.getColor(id); if (color != null) { return color; diff --git a/platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java b/platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java index f7bc0a94b7c4..d6f116895dc7 100644 --- a/platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java +++ b/platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java @@ -216,7 +216,9 @@ public class LinkLabel extends JLabel { } protected Color getTextColor() { - return myIsLinkActive ? getActive() : isVisited() ? getVisited() : getNormal(); + return myIsLinkActive ? getActive() : + myUnderline ? getHover() : + isVisited() ? getVisited() : getNormal(); } public void setPaintUnderline(boolean paintUnderline) { @@ -317,6 +319,10 @@ public class LinkLabel extends JLabel { return UI.getColor("link.foreground"); } + protected Color getHover() { + return UI.getColor("link.hover.foreground"); + } + public void entered(MouseEvent e) { enableUnderline(); } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJComboBoxUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJComboBoxUI.java index 95c5cc2cf76e..436f44021293 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJComboBoxUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJComboBoxUI.java @@ -19,7 +19,6 @@ import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; import com.intellij.ide.ui.laf.darcula.ui.DarculaComboBoxUI; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.registry.Registry; -import com.intellij.ui.ComboBoxCompositeEditor; import com.intellij.ui.EditorTextField; import com.intellij.ui.PopupMenuListenerAdapter; import com.intellij.util.ui.JBDimension; @@ -116,11 +115,13 @@ public class WinIntelliJComboBoxUI extends DarculaComboBoxUI { } } - g2.setColor(getComboBackground(editor != null && editor.isOpaque())); + boolean isOpaque = editor != null && editor.isOpaque(); + g2.setColor(getComboBackground(isOpaque)); JBInsets.removeFrom(r, JBUI.insets(2)); - if (!comboBox.isEnabled()) { - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.47f)); + if (!comboBox.isEnabled() && !isOpaque) { + float alpha = comboBox.isEditable() ? 0.35f : 0.47f; + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); } g2.fill(r); @@ -256,10 +257,6 @@ public class WinIntelliJComboBoxUI extends DarculaComboBoxUI { } } - if (!comboBox.isEnabled()) { - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); - } - Icon icon = MacIntelliJIconCache.getIcon("comboDropTriangle", false, false, isEnabled()); int x = JBUI.scale(5); int y = (getHeight() - icon.getIconHeight()) / 2; @@ -392,8 +389,7 @@ public class WinIntelliJComboBoxUI extends DarculaComboBoxUI { etf.addMouseListener(editorHoverListener); etf.setBackground(getComboBackground(true)); - int topBorderWidth = editor instanceof ComboBoxCompositeEditor ? 1 : 2; - jEditor.setBorder(JBUI.Borders.emptyTop(topBorderWidth)); + jEditor.setBorder(JBUI.Borders.emptyTop(1)); } } } @@ -460,7 +456,9 @@ public class WinIntelliJComboBoxUI extends DarculaComboBoxUI { } } else { g2.setColor(UIManager.getColor("Button.intellij.native.borderColor")); - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.47f)); + + float alpha = comboBox.isEditable() ? 0.35f : 0.47f; + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); } Path2D border = new Path2D.Double(Path2D.WIND_EVEN_ODD); @@ -505,7 +503,7 @@ public class WinIntelliJComboBoxUI extends DarculaComboBoxUI { @Override public Insets getBorderInsets(Component c) { return c.getComponentOrientation().isLeftToRight() ? - JBUI.insets(2, 6, 2, 2).asUIResource() : JBUI.insets(2, 2, 2, 6).asUIResource(); + JBUI.insets(2, 5, 2, 2).asUIResource() : JBUI.insets(2, 2, 2, 5).asUIResource(); } private Dimension getSizeWithButton(Dimension d) { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJSpinnerUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJSpinnerUI.java index 8954d331542a..1a3cb580f858 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJSpinnerUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJSpinnerUI.java @@ -225,7 +225,7 @@ public class WinIntelliJSpinnerUI extends DarculaSpinnerUI { Dimension prevButtonSize = prevButton.getPreferredSize(); prevButton.setBounds(bounds.width - prevButtonSize.width, nextButtonSize.height - JBUI.scale(1), - prevButtonSize.width, prevButtonSize.height); + prevButtonSize.width, bounds.height - nextButtonSize.height + JBUI.scale(1)); JComponent editor = spinner.getEditor(); if (editor != null) { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextBorder.java index 62e0dc290e3e..c29c6447050b 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextBorder.java @@ -44,7 +44,7 @@ public class WinIntelliJTextBorder extends DarculaTextBorder { } else if (c instanceof JTextField && c.getParent() instanceof ColorPanel) { return JBUI.insets(3, 3, 2, 2).asUIResource(); } else { - return JBUI.insets(4, 6).asUIResource(); + return JBUI.insets(4, 5).asUIResource(); } } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextFieldUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextFieldUI.java index ced1625d5a3d..41d3c89364c0 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextFieldUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextFieldUI.java @@ -85,7 +85,7 @@ public class WinIntelliJTextFieldUI extends DarculaTextFieldUI { } static void paintTextFieldBackground(JComponent c, Graphics2D g2) { - g2.setColor(c.isEnabled() ? c.getBackground() : UIManager.getColor("TextField.inactiveBackground")); + g2.setColor(c.isEnabled() ? c.getBackground() : UIManager.getColor("Button.background")); if (!c.isEnabled()) { g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.47f)); diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties index 496aa1c1c0be..abc6ed280be5 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties @@ -33,7 +33,10 @@ Menu.border=com.intellij.ide.ui.laf.darcula.ui.DarculaMenuItemBorder EditorPaneUI=com.intellij.ide.ui.laf.darcula.ui.DarculaEditorPaneUI control=f2f2f2 -link.foreground=589df6 +link.foreground=016cc1 +link.pressed.foreground=006064 +link.hover.foreground=00bcd4 +link.visited.foreground=016cc1 ScrollBarUI=com.intellij.ui.components.JBScrollBar TableHeaderUI=com.intellij.ide.ui.laf.darcula.DarculaTableHeaderUI Table.gridColor=dddddd diff --git a/platform/platform-impl/src/com/intellij/ide/util/GotoLineNumberDialog.java b/platform/platform-impl/src/com/intellij/ide/util/GotoLineNumberDialog.java index 6b322715a20d..9866caddad74 100644 --- a/platform/platform-impl/src/com/intellij/ide/util/GotoLineNumberDialog.java +++ b/platform/platform-impl/src/com/intellij/ide/util/GotoLineNumberDialog.java @@ -28,6 +28,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.DocumentEvent; import java.awt.*; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -80,6 +82,14 @@ public abstract class GotoLineNumberDialog extends DialogWrapper { class MyTextField extends JTextField { public MyTextField() { super(""); + addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + if (!e.isTemporary()) { + selectAll(); + } + } + }); } public Dimension getPreferredSize() { diff --git a/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java b/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java index dd15dd1bd930..2db9101370fd 100644 --- a/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java +++ b/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java @@ -29,6 +29,9 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.UserDataHolder; +import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.pom.Navigatable; @@ -61,7 +64,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * @param List item type. Must implement {@code equals()/hashCode()} correctly. * @since 13.0 */ -public abstract class FinderRecursivePanel extends OnePixelSplitter implements DataProvider, Disposable { +public abstract class FinderRecursivePanel extends OnePixelSplitter implements DataProvider, UserDataHolder, Disposable { @NotNull private final Project myProject; @@ -101,6 +104,8 @@ public abstract class FinderRecursivePanel extends OnePixelSplitter implement } }; + private final UserDataHolderBase myUserDataHolder = new UserDataHolderBase(); + protected FinderRecursivePanel(@NotNull FinderRecursivePanel parent) { this(parent.getProject(), parent, parent.getGroupId()); } @@ -385,6 +390,17 @@ public abstract class FinderRecursivePanel extends OnePixelSplitter implement return null; } + @Nullable + @Override + public U getUserData(@NotNull Key key) { + return myUserDataHolder.getUserData(key); + } + + @Override + public void putUserData(@NotNull Key key, @Nullable U value) { + myUserDataHolder.putUserData(key, value); + } + @Override public void dispose() { super.dispose(); @@ -692,4 +708,24 @@ public abstract class FinderRecursivePanel extends OnePixelSplitter implement protected final void customizeCellRenderer(@NotNull JList list, Object value, int index, boolean selected, boolean hasFocus) { } } + + /** + * {@link FinderRecursivePanel} disposes right component on selection change if it is disposable. + * If an inheritor creates disposable objects during right component creation, + * the disposable objects must be registered as children of the created right component + * in order to dispose created objects on selection change. + * {@link DisposablePanel} could be used as a right component in that case. + */ + protected static class DisposablePanel extends JPanel implements Disposable { + public DisposablePanel(LayoutManager layout, @Nullable Disposable parent) { + super(layout); + if (parent != null) { + Disposer.register(parent, this); + } + } + + @Override + public void dispose() { + } + } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ui/TreeExpandCollapse.java b/platform/platform-impl/src/com/intellij/ui/TreeExpandCollapse.java index baf86acc57b8..dfd3076583c2 100644 --- a/platform/platform-impl/src/com/intellij/ui/TreeExpandCollapse.java +++ b/platform/platform-impl/src/com/intellij/ui/TreeExpandCollapse.java @@ -31,9 +31,13 @@ public class TreeExpandCollapse { } public static void expandAll(JTree tree) { - TreePath path = tree.getSelectionPath(); - if (path == null) path = new TreePath(tree.getModel().getRoot()); - new ExpandContext(300, 10).expand(tree, path); + TreePath[] paths = tree.getSelectionPaths(); + if (paths == null) { + paths = new TreePath[] { new TreePath(tree.getModel().getRoot()) }; + } + for (TreePath path : paths) { + new ExpandContext(300, 10).expand(tree, path); + } } private static class ExpandContext { diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 96d8a8c99a98..17a365ef4d17 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -1318,7 +1318,6 @@ action.Diff.FocusOppositePaneAndScroll.text=Select Position In Opposite Diff Pan action.Diff.FocusOppositePaneAndScroll.description=Select the same position in opposite pane in diff view action.Diff.PrevChange.text=Compare Previous File action.Diff.NextChange.text=Compare Next File -action.Diff.SelectedChange.text=Choose File To Compare action.Diff.ApplyLeftSide.text=Accept Left Side action.Diff.ApplyRightSide.text=Accept Right Side action.Diff.AppendLeftSide.text=Append Left Side diff --git a/platform/platform-resources-en/src/messages/VcsBundle.properties b/platform/platform-resources-en/src/messages/VcsBundle.properties index 682a2e481980..b81cae50d33e 100644 --- a/platform/platform-resources-en/src/messages/VcsBundle.properties +++ b/platform/platform-resources-en/src/messages/VcsBundle.properties @@ -367,6 +367,7 @@ create.patch.success.confirmation=Successfully created patch {0} patch.apply.error=Failed to apply patch for file {0}: {1} patch.load.base.revision.error=Failed to load patch base revision for file {0}: {1} shelve.changes.only.directories=The selected changes affect only directories and no files, so they cannot be shelved +stash.changes.message=Uncommitted changes before {0} edit.errors=Edit Errors rollback.modified.without.editing.confirm.single=Would you like to {0} the changes to {1}? rollback.modified.without.editing.confirm.multiple=Would you like to {0} the changes to {1} selected files? diff --git a/platform/platform-resources/src/idea/VcsActions.xml b/platform/platform-resources/src/idea/VcsActions.xml index fb3f0a36184a..ecf6df0f61e5 100644 --- a/platform/platform-resources/src/idea/VcsActions.xml +++ b/platform/platform-resources/src/idea/VcsActions.xml @@ -218,8 +218,6 @@ icon="AllIcons.Actions.Prevfile" use-shortcut-of="PreviousTab"/> - @@ -381,7 +379,6 @@ - diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/encoding/FileEncodingTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/encoding/FileEncodingTest.java index 986f3753df1a..0d6483e37ddc 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/encoding/FileEncodingTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/encoding/FileEncodingTest.java @@ -50,6 +50,7 @@ import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ObjectUtils; import com.intellij.util.text.ByteArrayCharSequence; import com.intellij.util.text.XmlCharsetDetector; import com.intellij.util.ui.UIUtil; @@ -112,7 +113,7 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { } public void testXmlProlog() throws IOException { VirtualFile vTestRoot = getTestRoot(); - VirtualFile xml = vTestRoot.findChild("xNotepadUtf8.xml"); + VirtualFile xml = ObjectUtils.assertNotNull(vTestRoot.findChild("xNotepadUtf8.xml")); String expected = UTF8_XML_PROLOG + XML_TEST_BODY; String text = getDocument(xml).getText(); @@ -154,7 +155,7 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { } public void testChangeToUtfProlog() throws IOException { - VirtualFile src = getTestRoot().findChild("xWin1251.xml"); + VirtualFile src = find("xWin1251.xml"); final File dir = createTempDirectory(); final File file = new File(dir, "copy.xml"); FileUtil.copy(new File(src.getPath()), file); @@ -178,25 +179,30 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { } public void testDefaultHtml() { - VirtualFile file = getTestRoot().findChild("defaultHtml.html"); + VirtualFile file = find("defaultHtml.html"); assertEquals(EncodingProjectManager.getInstance(getProject()).getDefaultCharset(), file.getCharset()); } + @NotNull + private static VirtualFile find(String name) { + return ObjectUtils.assertNotNull(getTestRoot().findChild(name)); + } + public void testTrickyProlog() { - VirtualFile xml = getTestRoot().findChild("xTrickyProlog.xml"); + VirtualFile xml = find("xTrickyProlog.xml"); assertEquals("Big5", xml.getCharset().name()); } public void testDefaultXml() { - VirtualFile xml = getTestRoot().findChild("xDefault.xml"); + VirtualFile xml = find("xDefault.xml"); assertEquals(CharsetToolkit.UTF8_CHARSET, xml.getCharset()); } public void testIbm866() { - VirtualFile xml = getTestRoot().findChild("xIbm866.xml"); + VirtualFile xml = find("xIbm866.xml"); String expected = prolog(Charset.forName("IBM866")) + XML_TEST_BODY; String text = getDocument(xml).getText(); @@ -210,8 +216,7 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { } public void testUTF16BOM() throws IOException { - VirtualFile vTestRoot = getTestRoot(); - VirtualFile file = vTestRoot.findChild(getTestName(false) + ".txt"); + VirtualFile file = find(getTestName(false) + ".txt"); File source = new File(file.getPath()); byte[] bytesSource = FileUtil.loadFileBytes(source); assertTrue(Arrays.toString(bytesSource), CharsetToolkit.hasUTF16LEBom(bytesSource)); @@ -254,7 +259,7 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { WINDOWS_1252); myFilesToDelete.add(temp); - VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(temp); + VirtualFile file = ObjectUtils.assertNotNull(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(temp)); assertEquals(WINDOWS_1252, file.getCharset()); @@ -372,8 +377,10 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { public void testCopyMove() throws IOException { File root = createTempDirectory(); - File dir1 = new File(root, "dir1"); dir1.mkdir(); - File dir2 = new File(root, "dir2"); dir2.mkdir(); + File dir1 = new File(root, "dir1"); + assertTrue(dir1.mkdir()); + File dir2 = new File(root, "dir2"); + assertTrue(dir2.mkdir()); final VirtualFile vdir1 = getVirtualFile(dir1); final VirtualFile vdir2 = getVirtualFile(dir2); assertNotNull(dir1.getPath(), vdir1); @@ -402,8 +409,10 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { public void testCopyNested() throws IOException, IncorrectOperationException { File root = createTempDirectory(); - File dir1 = new File(root, "dir1"); dir1.mkdir(); - File dir2 = new File(root, "dir2"); dir2.mkdir(); + File dir1 = new File(root, "dir1"); + assertTrue(dir1.mkdir()); + File dir2 = new File(root, "dir2"); + assertTrue(dir2.mkdir()); final VirtualFile vdir1 = getVirtualFile(dir1); final VirtualFile vdir2 = getVirtualFile(dir2); assertNotNull(dir1.getPath(), vdir1); @@ -416,10 +425,10 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { protected void run() throws Throwable { VirtualFile winf = vdir1.createChildData(this, "xxx.txt"); - PsiDirectory psidir1 = PsiManager.getInstance(getProject()).findDirectory(vdir1); - PsiDirectory psidir2 = PsiManager.getInstance(getProject()).findDirectory(vdir2); + PsiDirectory psidir1 = ObjectUtils.assertNotNull(PsiManager.getInstance(getProject()).findDirectory(vdir1)); + PsiDirectory psidir2 = ObjectUtils.assertNotNull(PsiManager.getInstance(getProject()).findDirectory(vdir2)); CopyFilesOrDirectoriesHandler.copyToDirectory(psidir1, psidir1.getName(), psidir2); - VirtualFile winfCopy = psidir2.getVirtualFile().findFileByRelativePath(psidir1.getName() + "/" + winf.getName()); + VirtualFile winfCopy = ObjectUtils.assertNotNull(psidir2.getVirtualFile().findFileByRelativePath(psidir1.getName() + "/" + winf.getName())); assertEquals(WINDOWS_1251, winfCopy.getCharset()); VirtualFile dir1Copy = psidir2.getVirtualFile().findChild(psidir1.getName()); assertEquals(WINDOWS_1251, EncodingManager.getInstance().getEncoding(dir1Copy, false)); @@ -466,8 +475,7 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { } public void testVFileGetInputStreamIsBOMAware() throws IOException { - VirtualFile vTestRoot = getTestRoot(); - VirtualFile file = vTestRoot.findChild("UTF16BOM.txt"); + VirtualFile file = find("UTF16BOM.txt"); String vfsLoad = VfsUtilCore.loadText(file); assertEquals("\u041f\u0440\u0438", vfsLoad); @@ -478,8 +486,7 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { assertArrayEquals(CharsetToolkit.UTF16LE_BOM, file.getBOM()); } public void testSetCharsetAfter() throws IOException { - VirtualFile vTestRoot = getTestRoot(); - VirtualFile file = vTestRoot.findChild("UTF16LE_NOBOM.txt"); + VirtualFile file = find("UTF16LE_NOBOM.txt"); file.setCharset(CharsetToolkit.UTF_16LE_CHARSET); file.setBOM(null); String vfsLoad = VfsUtilCore.loadText(file); @@ -606,7 +613,7 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { public void testSetEncodingForDirectoryChangesEncodingsForEvenNotLoadedFiles() throws IOException { EncodingProjectManager.getInstance(getProject()).setEncoding(null, CharsetToolkit.UTF8_CHARSET); File fc = FileUtil.createTempDirectory("", ""); - VirtualFile root = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(fc); + VirtualFile root = ObjectUtils.assertNotNull(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(fc)); PsiTestUtil.addContentRoot(getModule(), root); VirtualFile file = createChildData(root, "win.txt"); @@ -693,7 +700,7 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { change(file, WINDOWS_1251); assertEquals(WINDOWS_1251, file.getCharset()); - Document document = documentManager.getDocument(file); + Document document = ObjectUtils.assertNotNull(documentManager.getDocument(file)); change(file, CharsetToolkit.UTF8_CHARSET); assertEquals(CharsetToolkit.UTF8_CHARSET, file.getCharset()); @@ -701,7 +708,7 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { UIUtil.dispatchAllInvocationEvents(); assertEquals(WINDOWS_1251, file.getCharset()); - document.getText(); + ObjectUtils.assertNotNull(document.getText()); } private void globalUndo() { @@ -718,7 +725,7 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { public void testCantReloadBOMDetected() throws IOException { VirtualFile file = createTempFile("txt", CharsetToolkit.UTF8_BOM, THREE_RUSSIAN_LETTERS, CharsetToolkit.UTF8_CHARSET); file.contentsToByteArray(); - Document document = FileDocumentManager.getInstance().getDocument(file); + Document document = ObjectUtils.assertNotNull(FileDocumentManager.getInstance().getDocument(file)); assertEquals(THREE_RUSSIAN_LETTERS, document.getText()); assertEquals(CharsetToolkit.UTF8_CHARSET, file.getCharset()); EncodingManager.getInstance().setEncoding(file, CharsetToolkit.UTF_16LE_CHARSET); @@ -731,7 +738,8 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { String text = "text"; VirtualFile file = createTempFile("txt", CharsetToolkit.UTF8_BOM, text, CharsetToolkit.UTF8_CHARSET); file.contentsToByteArray(); - Document document = FileDocumentManager.getInstance().getDocument(file); + Document document = ObjectUtils.assertNotNull(FileDocumentManager.getInstance().getDocument(file)); + assertEquals(text, document.getText()); assertEquals(CharsetToolkit.UTF8_CHARSET, file.getCharset()); assertArrayEquals(CharsetToolkit.UTF8_BOM, file.getBOM()); @@ -809,9 +817,10 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { EncodingManager.getInstance().setDefaultCharsetName(differentFromDefault); File temp = createTempDirectory(); - VirtualFile tempDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(temp); + VirtualFile tempDir = ObjectUtils.assertNotNull(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(temp)); - final Project newProject = ProjectManagerEx.getInstanceEx().newProject("new", tempDir.getPath(), false, false); + final Project newProject = + ObjectUtils.assertNotNull(ProjectManagerEx.getInstanceEx().newProject("new", tempDir.getPath(), false, false)); Disposer.register(getTestRootDisposable(), () -> ApplicationManager.getApplication().runWriteAction(() -> Disposer.dispose(newProject))); PlatformTestUtil.saveProject(newProject); @@ -829,14 +838,14 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { } public void testFileMustNotLoadInWrongEncodingIfAccessedBeforeProjectOpen() { - VirtualFile dir = getTestRoot().findChild("newEncoding"); - VirtualFile file = dir.findFileByRelativePath("src/xxx.txt"); + VirtualFile dir = find("newEncoding"); + VirtualFile file = ObjectUtils.assertNotNull(dir.findFileByRelativePath("src/xxx.txt")); - Document document = FileDocumentManager.getInstance().getDocument(file); - document.getText(); + Document document = ObjectUtils.assertNotNull(FileDocumentManager.getInstance().getDocument(file)); + ObjectUtils.assertNotNull(document.getText()); UIUtil.dispatchAllInvocationEvents(); - Project newEncodingProject = ProjectUtil.openProject(dir.getPath(), null, false); + Project newEncodingProject = ObjectUtils.assertNotNull(ProjectUtil.openProject(dir.getPath(), null, false)); UIUtil.dispatchAllInvocationEvents(); try { assertEquals(US_ASCII, file.getCharset()); @@ -906,7 +915,7 @@ public class FileEncodingTest extends PlatformTestCase implements TestDialog { File file = createTempFile("a.txt", text); setContentOnDisk(file, null, text, CharsetToolkit.UTF_16LE_CHARSET); - VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); + VirtualFile vFile = ObjectUtils.assertNotNull(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file)); vFile.setCharset(CharsetToolkit.UTF_16LE_CHARSET); vFile.setBOM(null); CharSequence loaded = LoadTextUtil.loadText(vFile); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/CoreJarFileSystemTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/CoreJarFileSystemTest.java index e74e817fb813..4d4aa6f69c97 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/CoreJarFileSystemTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/CoreJarFileSystemTest.java @@ -19,6 +19,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.UsefulTestCase; +import com.intellij.util.ObjectUtils; /** * @author yole @@ -27,7 +28,7 @@ public class CoreJarFileSystemTest extends UsefulTestCase{ public void testSimple() { CoreJarFileSystem fs = new CoreJarFileSystem(); String jarPath = PlatformTestUtil.getPlatformTestDataPath() + "vfs/corejar/rt.jar"; - VirtualFile root = fs.findFileByPath(jarPath + "!/"); + VirtualFile root = ObjectUtils.assertNotNull(fs.findFileByPath(jarPath + "!/")); VirtualFile[] children = root.getChildren(); assertEquals(4, children.length); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerTest.java index 35d241b90e70..534663d64ce8 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerTest.java @@ -763,7 +763,7 @@ public class VirtualFilePointerTest extends PlatformTestCase { final LoggingListener listener = new LoggingListener(); final String url = VfsUtilCore.pathToUrl("/a/b/c/d/e"); final VirtualFilePointer thePointer = myVirtualFilePointerManager.create(url, disposable, listener); - TempFileSystem.getInstance(); + assertNotNull(TempFileSystem.getInstance()); PlatformTestUtil.startPerformanceTest("same url vfp create", 9000, () -> { for (int i = 0; i < 10_000_000; i++) { VirtualFilePointer pointer = myVirtualFilePointerManager.create(url, disposable, listener); @@ -962,6 +962,7 @@ public class VirtualFilePointerTest extends PlatformTestCase { ready.await(); VirtualFilePointer bc = VirtualFilePointerManager.getInstance().create(fileToCreatePointer.getUrl() + "/b/c", disposable, listener); + assertNotNull(bc); run = false; ConcurrencyUtil.joinAll(threads); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/local/CanonicalPathMapTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/local/CanonicalPathMapTest.java index cecd6d5b59e7..fcee8b1ac143 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/local/CanonicalPathMapTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/local/CanonicalPathMapTest.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vfs.impl.local; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.IoTestUtil; import com.intellij.testFramework.rules.TempDirectory; @@ -25,10 +26,8 @@ import org.junit.Test; import java.io.File; import java.io.IOException; import java.util.Collection; +import java.util.Collections; -import static com.intellij.openapi.util.Pair.pair; -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; public class CanonicalPathMapTest { @@ -42,7 +41,7 @@ public class CanonicalPathMapTest { @Test public void flatRootReportedExactlyViaParent() { String root = DIR_ROOT; - CanonicalPathMap map = new CanonicalPathMap(emptyList(), singletonList(root)); + CanonicalPathMap map = new CanonicalPathMap(Collections.emptyList(), Collections.singletonList(root)); Collection paths = map.getWatchedPaths(PathUtil.getParentPath(root), true); assertThat(paths).isEmpty(); } @@ -50,15 +49,16 @@ public class CanonicalPathMapTest { @Test public void flatRootReportedExactlyViaItself() { String root = FILE_ROOT; - CanonicalPathMap map = new CanonicalPathMap(emptyList(), singletonList(root)); + CanonicalPathMap map = new CanonicalPathMap(Collections.emptyList(), Collections.singletonList(root)); Collection paths = map.getWatchedPaths(root, true); assertThat(paths).containsExactly(root); } @Test public void flatRootReportedExactlyViaChild() { - String root = DIR_ROOT, child = root + CHILD_FILE; - CanonicalPathMap map = new CanonicalPathMap(emptyList(), singletonList(root)); + String root = DIR_ROOT; + String child = root + CHILD_FILE; + CanonicalPathMap map = new CanonicalPathMap(Collections.emptyList(), Collections.singletonList(root)); Collection paths = map.getWatchedPaths(child, true); assertThat(paths).containsExactly(child); } @@ -66,7 +66,7 @@ public class CanonicalPathMapTest { @Test public void flatRootReportedInexactlyViaParent() { String root = FILE_ROOT; - CanonicalPathMap map = new CanonicalPathMap(emptyList(), singletonList(root)); + CanonicalPathMap map = new CanonicalPathMap(Collections.emptyList(), Collections.singletonList(root)); Collection paths = map.getWatchedPaths(PathUtil.getParentPath(root), false); assertThat(paths).containsExactly(root); } @@ -74,15 +74,16 @@ public class CanonicalPathMapTest { @Test public void flatRootReportedInexactlyViaItself() { String root = DIR_ROOT; - CanonicalPathMap map = new CanonicalPathMap(emptyList(), singletonList(root)); + CanonicalPathMap map = new CanonicalPathMap(Collections.emptyList(), Collections.singletonList(root)); Collection paths = map.getWatchedPaths(root, false); assertThat(paths).containsExactly(root); } @Test public void flatRootReportedInexactlyViaChild() { - String root = DIR_ROOT, child = root + CHILD_DIR; - CanonicalPathMap map = new CanonicalPathMap(emptyList(), singletonList(root)); + String root = DIR_ROOT; + String child = root + CHILD_DIR; + CanonicalPathMap map = new CanonicalPathMap(Collections.emptyList(), Collections.singletonList(root)); Collection paths = map.getWatchedPaths(child, false); assertThat(paths).isEmpty(); } @@ -90,7 +91,7 @@ public class CanonicalPathMapTest { @Test public void recursiveRootReportedExactlyViaParent() { String root = DIR_ROOT; - CanonicalPathMap map = new CanonicalPathMap(singletonList(root), emptyList()); + CanonicalPathMap map = new CanonicalPathMap(Collections.singletonList(root), Collections.emptyList()); Collection paths = map.getWatchedPaths(PathUtil.getParentPath(root), true); assertThat(paths).isEmpty(); } @@ -98,15 +99,16 @@ public class CanonicalPathMapTest { @Test public void recursiveRootReportedExactlyViaItself() { String root = DIR_ROOT; - CanonicalPathMap map = new CanonicalPathMap(singletonList(root), emptyList()); + CanonicalPathMap map = new CanonicalPathMap(Collections.singletonList(root), Collections.emptyList()); Collection paths = map.getWatchedPaths(root, true); assertThat(paths).containsExactly(root); } @Test public void recursiveRootReportedExactlyViaChild() { - String root = DIR_ROOT, child = root + CHILD_FILE; - CanonicalPathMap map = new CanonicalPathMap(singletonList(root), emptyList()); + String root = DIR_ROOT; + String child = root + CHILD_FILE; + CanonicalPathMap map = new CanonicalPathMap(Collections.singletonList(root), Collections.emptyList()); Collection paths = map.getWatchedPaths(child, true); assertThat(paths).containsExactly(child); } @@ -114,7 +116,7 @@ public class CanonicalPathMapTest { @Test public void recursiveRootReportedInexactlyViaParent() { String root = DIR_ROOT; - CanonicalPathMap map = new CanonicalPathMap(singletonList(root), emptyList()); + CanonicalPathMap map = new CanonicalPathMap(Collections.singletonList(root), Collections.emptyList()); Collection paths = map.getWatchedPaths(PathUtil.getParentPath(root), false); assertThat(paths).containsExactly(root); } @@ -122,15 +124,16 @@ public class CanonicalPathMapTest { @Test public void recursiveRootReportedInexactlyViaItself() { String root = DIR_ROOT; - CanonicalPathMap map = new CanonicalPathMap(singletonList(root), emptyList()); + CanonicalPathMap map = new CanonicalPathMap(Collections.singletonList(root), Collections.emptyList()); Collection paths = map.getWatchedPaths(root, false); assertThat(paths).containsExactly(root); } @Test public void recursiveRootReportedInexactlyViaChild() { - String root = DIR_ROOT, child = root + CHILD_DIR; - CanonicalPathMap map = new CanonicalPathMap(singletonList(root), emptyList()); + String root = DIR_ROOT; + String child = root + CHILD_DIR; + CanonicalPathMap map = new CanonicalPathMap(Collections.singletonList(root), Collections.emptyList()); Collection paths = map.getWatchedPaths(child, false); assertThat(paths).containsExactly(child); } @@ -143,10 +146,10 @@ public class CanonicalPathMapTest { File mappedDir = new File(myTempDir.getRoot(), "mapped"); // Initial symlink map: /?/root/link_dir -> /?/root/real - CanonicalPathMap pathMap = new CanonicalPathMap(singletonList(symLink.getPath()), emptyList()); + CanonicalPathMap pathMap = new CanonicalPathMap(Collections.singletonList(symLink.getPath()), Collections.emptyList()); // REMAP from native file watcher: /?/root/mapped -> /?/root/real - pathMap.addMapping(singletonList(pair(mappedDir.getPath(), realDir.getPath()))); + pathMap.addMapping(Collections.singletonList(Pair.pair(mappedDir.getPath(), realDir.getPath()))); Collection watchedPaths = pathMap.getWatchedPaths(new File(mappedDir, "file.txt").getPath(), true); assertThat(watchedPaths).containsExactly(new File(symLink, "file.txt").getPath()); diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfoWithExcludePatterns.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfoWithExcludePatterns.java index d647f8f53e7b..8bc920a1b4bd 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfoWithExcludePatterns.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfoWithExcludePatterns.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.roots.impl; +import com.intellij.injected.editor.VirtualFileWindow; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.impl.FileTypeAssocTable; import com.intellij.openapi.module.Module; @@ -51,7 +52,7 @@ public class DirectoryInfoWithExcludePatterns extends DirectoryInfoImpl { private boolean isExcludedByPatterns(@NotNull VirtualFile file, @Nullable FileTypeAssocTable patterns) { if (patterns == null) return false; - VirtualFile current = file; + VirtualFile current = getPhysicalFile(file); while (current != null && !myRoot.equals(current)) { if (patterns.findAssociatedFileType(current.getNameSequence()) != null) { return true; @@ -64,6 +65,10 @@ public class DirectoryInfoWithExcludePatterns extends DirectoryInfoImpl { return false; } + private static VirtualFile getPhysicalFile(VirtualFile file) { + return file instanceof VirtualFileWindow ? ((VirtualFileWindow)file).getDelegate() : file; + } + @Override public boolean isExcluded(@NotNull VirtualFile file) { if (myExcluded) return true; @@ -75,7 +80,7 @@ public class DirectoryInfoWithExcludePatterns extends DirectoryInfoImpl { boolean inContent = getContentRoot() != null; if (!inContent && !myInLibrarySource) return false; - VirtualFile current = file; + VirtualFile current = getPhysicalFile(file); while (current != null && !myRoot.equals(current)) { CharSequence name = current.getNameSequence(); boolean excludedFromModule = myContentExcludePatterns != null && myContentExcludePatterns.findAssociatedFileType(name) != null; diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/RemoteServerListConfigurableProvider.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/RemoteServerListConfigurableProvider.java index 0da148995892..f2f65794e212 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/RemoteServerListConfigurableProvider.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/RemoteServerListConfigurableProvider.java @@ -20,6 +20,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurableEP; import com.intellij.openapi.options.ConfigurableProvider; +import com.intellij.openapi.options.UnnamedConfigurable; import com.intellij.remoteServer.ServerType; import com.intellij.remoteServer.configuration.RemoteServersManager; import com.intellij.util.containers.ContainerUtil; @@ -27,7 +28,9 @@ import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * @author Sergey.Malenkov @@ -47,21 +50,23 @@ public final class RemoteServerListConfigurableProvider extends ConfigurableProv @NotNull private static List> getServerTypesInCloudsList() { Application application = ApplicationManager.getApplication(); - List> excludedTypes = Arrays.stream(application.getExtensions(Configurable.APPLICATION_CONFIGURABLE)) - .filter(RemoteServerListConfigurableProvider::isRemoteServerListConfigurable) - .filter(ConfigurableEP::canCreateConfigurable) - .map(ConfigurableEP::createConfigurable) - .map(RemoteServerListConfigurable.class::cast) - .map(RemoteServerListConfigurable::getDisplayedServerTypes) - .flatMap(List::stream) - .collect(Collectors.toList()); + Set> excludedTypes = Arrays.stream(application.getExtensions(Configurable.APPLICATION_CONFIGURABLE)) + .flatMap(RemoteServerListConfigurableProvider::tryGetServerTypes) + .collect(Collectors.toSet()); ServerType[] allServerTypes = ServerType.EP_NAME.getExtensions(); return ContainerUtil.filter(allServerTypes, t -> !excludedTypes.contains(t)); } - private static boolean isRemoteServerListConfigurable(@NotNull ConfigurableEP ep) { + @NotNull + private static Stream> tryGetServerTypes(@NotNull ConfigurableEP ep) { Class type = ep.getConfigurableType(); - return type != null && RemoteServerListConfigurable.class.isAssignableFrom(type); + if (type != null && RemoteServerListConfigurable.class.isAssignableFrom(type)) { + UnnamedConfigurable configurable = ep.createConfigurable(); + if (configurable instanceof RemoteServerListConfigurable) { + return ((RemoteServerListConfigurable)configurable).getDisplayedServerTypes().stream(); + } + } + return Stream.empty(); } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceUsageViewContext.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceUsageViewContext.java index 9728828facf3..f71d1b7fc6ef 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceUsageViewContext.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceUsageViewContext.java @@ -19,6 +19,7 @@ import com.intellij.history.LocalHistory; import com.intellij.history.LocalHistoryAction; import com.intellij.openapi.vfs.ReadonlyStatusHandler; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; import com.intellij.structuralsearch.MatchResult; import com.intellij.structuralsearch.SSRBundle; import com.intellij.structuralsearch.plugin.replace.ReplacementInfo; @@ -26,21 +27,19 @@ import com.intellij.structuralsearch.plugin.replace.impl.Replacer; import com.intellij.structuralsearch.plugin.ui.Configuration; import com.intellij.structuralsearch.plugin.ui.SearchContext; import com.intellij.structuralsearch.plugin.ui.UsageViewContext; -import com.intellij.usageView.UsageInfo; import com.intellij.usages.Usage; import com.intellij.usages.UsageInfo2UsageAdapter; import com.intellij.usages.UsageView; +import com.intellij.util.ObjectUtils; +import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Set; +import java.util.*; +import java.util.stream.Collectors; class ReplaceUsageViewContext extends UsageViewContext { private final HashMap usage2ReplacementInfo = new HashMap<>(); private final Replacer replacer = new Replacer(mySearchContext.getProject(), ((ReplaceConfiguration)myConfiguration).getReplaceOptions()); private UsageView myUsageView; - private Set myExcludedSet; ReplaceUsageViewContext(SearchContext context, Configuration configuration, Runnable searchStarter) { super(configuration, context, searchStarter); @@ -51,128 +50,86 @@ class ReplaceUsageViewContext extends UsageViewContext { myUsageView = usageView; } - public Replacer getReplacer() { - return replacer; - } - public void addReplaceUsage(Usage usage, MatchResult result) { - usage2ReplacementInfo.put(usage, getReplacer().buildReplacement(result)); + usage2ReplacementInfo.put(usage, replacer.buildReplacement(result)); } - private boolean isValid(UsageInfo2UsageAdapter info) { - final UsageInfo usageInfo = info.getUsageInfo(); - return !isExcluded(info) && usageInfo.getElement() != null && usageInfo.getElement().isValid(); + private static boolean isValid(UsageInfo2UsageAdapter info) { + final PsiElement element = info.getUsageInfo().getElement(); + return element != null && element.isValid(); } @Override protected void configureActions() { - final Runnable replaceRunnable = () -> { - LocalHistoryAction labelAction = LocalHistory.getInstance().startAction(SSRBundle.message("structural.replace.title")); - - doReplace(); - myUsageView.close(); - - labelAction.finish(); - }; - - //noinspection HardCodedStringLiteral - myUsageView.addPerformOperationAction(replaceRunnable, "Replace All", null, SSRBundle.message("do.replace.all.button")); - - final Runnable replaceSelected = () -> { - final Set infos = myUsageView.getSelectedUsages(); - if (infos == null || infos.isEmpty()) return; - - LocalHistoryAction labelAction = LocalHistory.getInstance().startAction(SSRBundle.message("structural.replace.title")); - - for (final Usage info : infos) { - final UsageInfo2UsageAdapter usage = (UsageInfo2UsageAdapter)info; - - if (isValid(usage)) { - replaceOne(usage, false); - } - } - - labelAction.finish(); - - if (myUsageView.getUsagesCount() > 0) { - for (Usage usage : myUsageView.getSortedUsages()) { - if (!isExcluded(usage)) { - myUsageView.selectUsages(new Usage[]{usage}); - return; - } - } - } - }; - - myUsageView.addButtonToLowerPane(replaceSelected, SSRBundle.message("replace.selected.button")); + myUsageView.addButtonToLowerPane(() -> replace(myUsageView.getSortedUsages()), SSRBundle.message("do.replace.all.button")); + myUsageView.addButtonToLowerPane(() -> replace(myUsageView.getSelectedUsages()), SSRBundle.message("replace.selected.button")); final Runnable previewReplacement = () -> { - Set selection = myUsageView.getSelectedUsages(); - - if (selection != null && !selection.isEmpty()) { - UsageInfo2UsageAdapter usage = (UsageInfo2UsageAdapter)selection.iterator().next(); - - if (isValid(usage)) { - replaceOne(usage, true); + final Set selection = myUsageView.getSelectedUsages(); + if (selection.isEmpty()) { + return; + } + for (Usage usage : selection) { + final UsageInfo2UsageAdapter info = (UsageInfo2UsageAdapter)usage; + if (!isValid(info) || myUsageView.getExcludedUsages().contains(usage)) { + continue; } + final ReplacementInfo replacementInfo = usage2ReplacementInfo.get(usage); + final ReplacementPreviewDialog previewDialog = + new ReplacementPreviewDialog(mySearchContext.getProject(), info.getUsageInfo(), replacementInfo.getReplacement()); + if (!previewDialog.showAndGet()) { + return; + } + replace(Collections.singleton(info)); } }; - myUsageView.addButtonToLowerPane(previewReplacement, SSRBundle.message("preview.replacement.button")); - - super.configureActions(); } - private static void ensureFileWritable(final UsageInfo2UsageAdapter usage) { - final VirtualFile file = usage.getFile(); + private void replace(@NotNull Collection usages) { + final Set excluded = myUsageView.getExcludedUsages(); + usages = usages.stream().filter(u -> !excluded.contains(u)).filter(u -> isValid((UsageInfo2UsageAdapter)u)).collect(Collectors.toList()); - if (file != null && !file.isWritable()) { - ReadonlyStatusHandler.getInstance(usage.getElement().getProject()).ensureFilesWritable(file); + final List files = usages.stream().map(i -> ((UsageInfo2UsageAdapter)i).getFile()).collect(Collectors.toList()); + if (ReadonlyStatusHandler.getInstance(mySearchContext.getProject()).ensureFilesWritable(files).hasReadonlyFiles()) { + return; + } + removeUsagesAndSelectNext(usages, excluded); + final LocalHistoryAction action = LocalHistory.getInstance().startAction(SSRBundle.message("structural.replace.title")); + try { + replacer.replaceAll(usages.stream().map(usage2ReplacementInfo::get).collect(Collectors.toList())); + } finally { + action.finish(); } } - private void replaceOne(UsageInfo2UsageAdapter info, boolean doConfirm) { - ReplacementInfo replacementInfo = usage2ReplacementInfo.get(info); - boolean approved; - - if (doConfirm) { - ReplacementPreviewDialog wrapper = - new ReplacementPreviewDialog(mySearchContext.getProject(), info.getUsageInfo(), replacementInfo.getReplacement()); - - approved = wrapper.showAndGet(); + private void removeUsagesAndSelectNext(Collection usages, Collection excluded) { + final List sortedUsages = myUsageView.getSortedUsages(); + if (sortedUsages.size() == usages.size()) { + myUsageView.close(); } else { - approved = true; - } - - if (approved) { - ensureFileWritable(info); - myUsageView.removeUsage(info); - getReplacer().replace(replacementInfo); - - if (myUsageView.getUsagesCount() == 0) { - myUsageView.close(); + Usage firstValid = null; + Usage select = null; + for (Usage usage : sortedUsages) { + if (usages.contains(usage)) { + select = null; + continue; + } + if (excluded.contains(usage) || !isValid((UsageInfo2UsageAdapter)usage)) { + continue; + } + if (select == null) { + select = usage; + } + if (firstValid == null) { + firstValid = usage; + } } + myUsageView.removeUsagesBulk(usages); + myUsageView.selectUsages(new Usage[]{ + ObjectUtils.coalesce(select, firstValid, myUsageView.getSortedUsages().get(0)) + }); } } - - private void doReplace() { - List infos = myUsageView.getSortedUsages(); - List results = new ArrayList<>(infos.size()); - - for (final Usage info : infos) { - UsageInfo2UsageAdapter usage = (UsageInfo2UsageAdapter)info; - - if (isValid(usage)) { - results.add(usage2ReplacementInfo.get(usage)); - } - } - - getReplacer().replaceAll(results); - } - - private boolean isExcluded(Usage usage) { - if (myExcludedSet == null) myExcludedSet = myUsageView.getExcludedUsages(); - return myExcludedSet.contains(usage); - } } diff --git a/platform/usageView/src/com/intellij/usages/UsageView.java b/platform/usageView/src/com/intellij/usages/UsageView.java index 82fa8851feb7..2e93e9354f3d 100644 --- a/platform/usageView/src/com/intellij/usages/UsageView.java +++ b/platform/usageView/src/com/intellij/usages/UsageView.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,8 +81,7 @@ public interface UsageView extends Disposable { @NotNull Set getExcludedUsages(); - @Nullable - Set getSelectedUsages(); + @NotNull Set getSelectedUsages(); @NotNull Set getUsages(); @NotNull List getSortedUsages(); diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java index 11cd89d8eaa7..e7bf59a5ece3 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java @@ -1470,12 +1470,12 @@ public class UsageViewImpl implements UsageView { } @Override - @Nullable + @NotNull public Set getSelectedUsages() { ApplicationManager.getApplication().assertIsDispatchThread(); TreePath[] selectionPaths = myTree.getSelectionPaths(); if (selectionPaths == null) { - return null; + return Collections.emptySet(); } Set usages = new THashSet<>(); @@ -1679,7 +1679,7 @@ public class UsageViewImpl implements UsageView { else if (key == USAGES_KEY) { final Set selectedUsages = getSelectedUsages(); - sink.put(USAGES_KEY, selectedUsages != null ? selectedUsages.toArray(new Usage[selectedUsages.size()]) : null); + sink.put(USAGES_KEY, selectedUsages.toArray(new Usage[selectedUsages.size()])); } else if (key == USAGE_TARGETS_KEY) { diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index f6b7fbd388a8..4b3ba4d69007 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -178,9 +178,6 @@ editor.smarterSelectionQuoting=true editor.skip.copy.and.cut.for.empty.selection=false editor.distraction.free.mode=false -editor.durable.folding.state=true -editor.durable.folding.state.description=If set, collapsed fold regions will preserve their state after a wider variety of document editing changes - editor.soft.wrap.force.limit=10000 editor.soft.wrap.force.limit.description=If document contains lines longer than this value, soft wraps will be forcibly enabled in editor due to performance reasons diff --git a/platform/util/src/com/intellij/openapi/progress/ProcessCanceledException.java b/platform/util/src/com/intellij/openapi/progress/ProcessCanceledException.java index 598fd86f2c61..de0e2f1ed52f 100644 --- a/platform/util/src/com/intellij/openapi/progress/ProcessCanceledException.java +++ b/platform/util/src/com/intellij/openapi/progress/ProcessCanceledException.java @@ -16,12 +16,12 @@ package com.intellij.openapi.progress; import com.intellij.openapi.diagnostic.ControlFlowException; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class ProcessCanceledException extends RuntimeException implements ControlFlowException { public ProcessCanceledException() { } - public ProcessCanceledException(@NotNull Throwable cause) { + public ProcessCanceledException(@Nullable Throwable cause) { super(cause); if (cause instanceof ProcessCanceledException) { throw new IllegalArgumentException("Must not self-wrap ProcessCanceledException: " + cause); diff --git a/platform/util/src/com/intellij/openapi/util/DefaultJDOMExternalizer.java b/platform/util/src/com/intellij/openapi/util/DefaultJDOMExternalizer.java index fa87820681d0..fbc5dc112a09 100644 --- a/platform/util/src/com/intellij/openapi/util/DefaultJDOMExternalizer.java +++ b/platform/util/src/com/intellij/openapi/util/DefaultJDOMExternalizer.java @@ -289,8 +289,7 @@ public class DefaultJDOMExternalizer { throw new InvalidDataException("wrong type: " + type); } } - catch (NoSuchFieldException ex) { - LOG.debug("No field '" + fieldName + "' in " + data.getClass(), ex); + catch (NoSuchFieldException ignore) { } catch (SecurityException ex) { throw new InvalidDataException(); diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentWeakFactoryMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentWeakFactoryMap.java index c360763401c5..b5bb50b037a5 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentWeakFactoryMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentWeakFactoryMap.java @@ -16,6 +16,8 @@ package com.intellij.util.containers; +import org.jetbrains.annotations.NotNull; + import java.util.Map; /** @@ -23,6 +25,7 @@ import java.util.Map; */ public abstract class ConcurrentWeakFactoryMap extends FactoryMap{ + @NotNull @Override protected Map createMap() { return ContainerUtil.createConcurrentWeakMap(); diff --git a/platform/util/src/com/intellij/util/containers/FactoryMap.java b/platform/util/src/com/intellij/util/containers/FactoryMap.java index 2832ffdf55e0..1a61f13d0128 100644 --- a/platform/util/src/com/intellij/util/containers/FactoryMap.java +++ b/platform/util/src/com/intellij/util/containers/FactoryMap.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.RecursionManager; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.Function; import com.intellij.util.ObjectUtils; +import com.intellij.util.Producer; import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -178,4 +179,21 @@ public abstract class FactoryMap implements Map { } }; } + + @NotNull + public static FactoryMap createMap(@NotNull final Producer> createMap, @NotNull final Function computeValue) { + return new FactoryMap() { + @NotNull + @Override + protected Map createMap() { + return createMap.produce(); + } + + @Nullable + @Override + protected V create(K key) { + return computeValue.fun(key); + } + }; + } } diff --git a/platform/util/util.iml b/platform/util/util.iml index 4dc58a08b7fa..2bdfa029d932 100644 --- a/platform/util/util.iml +++ b/platform/util/util.iml @@ -17,7 +17,6 @@ - diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangeListModification.java b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangeListModification.java index 31bad2ed1340..7c043c937732 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangeListModification.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangeListModification.java @@ -20,6 +20,8 @@ import org.jetbrains.annotations.Nullable; public interface ChangeListModification { LocalChangeList addChangeList(@NotNull String name, @Nullable final String comment); + + void setDefaultChangeList(@NotNull String name); void setDefaultChangeList(@NotNull LocalChangeList list); void removeChangeList(final String name); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java index 4c3556c8a674..25b6c2cdc70d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java @@ -904,15 +904,20 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } @Override - public void setDefaultChangeList(@NotNull final LocalChangeList list) { + public void setDefaultChangeList(@NotNull String name) { ApplicationManager.getApplication().runReadAction(() -> { synchronized (myDataLock) { - myModifier.setDefault(list.getName()); + myModifier.setDefault(name); } }); myChangesViewManager.scheduleRefresh(); } + @Override + public void setDefaultChangeList(@NotNull final LocalChangeList list) { + setDefaultChangeList(list.getName()); + } + @NotNull @Override public LocalChangeList getDefaultChangeList() { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListUtil.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListUtil.java deleted file mode 100644 index ceb2f3518326..000000000000 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListUtil.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2000-2015 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.vcs.changes; - -import com.google.common.primitives.Ints; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.List; - -public class ChangeListUtil { - - @Nullable - public static LocalChangeList getPredefinedChangeList(@NotNull String defaultName, @NotNull ChangeListManager changeListManager) { - final LocalChangeList sameNamedList = changeListManager.findChangeList(defaultName); - if (sameNamedList != null) return sameNamedList; - return tryToMatchWithExistingChangelist(changeListManager, defaultName); - } - - @Nullable - private static LocalChangeList tryToMatchWithExistingChangelist(@NotNull ChangeListManager changeListManager, - @NotNull final String defaultName) { - List matched = ContainerUtil.findAll(changeListManager.getChangeListsCopy(), - list -> defaultName.contains(list.getName().trim())); - - return matched.isEmpty() ? null : Collections.max(matched, - (o1, o2) -> Ints.compare(o1.getName().trim().length(), o2.getName().trim().length())); - } -} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListUtil.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListUtil.kt new file mode 100644 index 000000000000..3d01bc38abed --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListUtil.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2015 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.vcs.changes + +import com.intellij.openapi.vcs.VcsBundle +import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList + +object ChangeListUtil { + + private val CHANGELIST_NAME_PATTERN = "\\s\\[([\\s\\S]*)\\]" + private val STASH_MESSAGE_PATTERN = VcsBundle.message("stash.changes.message", "[\\s\\S]*") + private val SYSTEM_CHANGELIST_REGEX = (STASH_MESSAGE_PATTERN + CHANGELIST_NAME_PATTERN).toRegex() + + @JvmStatic fun createSystemShelvedChangeListName(systemPrefix: String, changelistName: String): String { + return "$systemPrefix [$changelistName]" + } + + fun getOriginalName(shelvedName: String): String { + return SYSTEM_CHANGELIST_REGEX.matchEntire(shelvedName)?.groups?.get(1)?.value ?: shelvedName + } + + @JvmStatic fun getPredefinedChangeList(shelvedList: ShelvedChangeList, changeListManager: ChangeListManager): LocalChangeList? { + val defaultName = shelvedList.DESCRIPTION + return changeListManager.findChangeList(defaultName) ?: + if (shelvedList.isMarkedToDelete) changeListManager.findChangeList(getOriginalName(defaultName)) else null + } + + @JvmStatic fun getChangeListNameForUnshelve(shelvedList: ShelvedChangeList): String { + val defaultName = shelvedList.DESCRIPTION + return if (shelvedList.isMarkedToDelete) getOriginalName(defaultName) else defaultName + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java index 06d4c45c44b4..84acd3ef3091 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java @@ -78,6 +78,7 @@ import java.util.concurrent.TimeUnit; import static com.intellij.openapi.util.io.FileUtil.toSystemIndependentName; import static com.intellij.openapi.vcs.changes.ChangeListUtil.getPredefinedChangeList; +import static com.intellij.openapi.vcs.changes.ChangeListUtil.getChangeListNameForUnshelve; import static com.intellij.util.ObjectUtils.chooseNotNull; public class ShelveChangesManager extends AbstractProjectComponent implements JDOMExternalizable { @@ -791,14 +792,9 @@ public class ShelveChangesManager extends AbstractProjectComponent implements JD @NotNull private LocalChangeList getChangeListUnshelveTo(@NotNull ShelvedChangeList list) { - String changeListName = list.DESCRIPTION; ChangeListManager manager = ChangeListManager.getInstance(myProject); - LocalChangeList localChangeList = manager.findChangeList(changeListName); - if (localChangeList != null) return localChangeList; - if (list.isMarkedToDelete()) { - localChangeList = getPredefinedChangeList(changeListName, manager); - } - return localChangeList != null ? localChangeList : manager.addChangeList(changeListName, ""); + LocalChangeList localChangeList = getPredefinedChangeList(list, manager); + return localChangeList != null ? localChangeList : manager.addChangeList(getChangeListNameForUnshelve(list), ""); } private class BinaryPatchApplier implements CustomBinaryPatchApplier { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/UnshelveWithDialogAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/UnshelveWithDialogAction.java index 3df376d25ad7..d21d41049c8d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/UnshelveWithDialogAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/UnshelveWithDialogAction.java @@ -46,6 +46,7 @@ import java.util.Collections; import java.util.List; import static com.intellij.openapi.vcs.changes.ChangeListUtil.getPredefinedChangeList; +import static com.intellij.openapi.vcs.changes.ChangeListUtil.getChangeListNameForUnshelve; import static com.intellij.openapi.vcs.changes.shelf.ShelvedChangesViewManager.getBinaryShelveChanges; import static com.intellij.openapi.vcs.changes.shelf.ShelvedChangesViewManager.getShelveChanges; import static com.intellij.util.containers.ContainerUtil.newArrayList; @@ -116,13 +117,10 @@ public class UnshelveWithDialogAction extends DumbAwareAction { @NotNull ShelvedChangeList changeList, @NotNull List binaryShelvedPatches, @Nullable Change[] preselectedChanges) { - super(project, new UnshelvePatchDefaultExecutor(project, changeList), - Collections.emptyList(), ApplyPatchMode.UNSHELVE, - patchFile, null, - changeList.isMarkedToDelete() ? getPredefinedChangeList(changeList.DESCRIPTION, ChangeListManager.getInstance(project)) : null, - binaryShelvedPatches, + super(project, new UnshelvePatchDefaultExecutor(project, changeList), Collections.emptyList(), ApplyPatchMode.UNSHELVE, patchFile, + null, getPredefinedChangeList(changeList, ChangeListManager.getInstance(project)), binaryShelvedPatches, hasNotAllSelectedChanges(project, changeList, preselectedChanges) ? newArrayList(preselectedChanges) : null, - changeList.DESCRIPTION, true); + getChangeListNameForUnshelve(changeList), true); } @Nullable diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java index 9954ce9f0e96..7862563ddf41 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java @@ -54,17 +54,13 @@ import static com.intellij.openapi.progress.ProgressManager.progress; import static com.intellij.openapi.ui.Messages.getQuestionIcon; import static com.intellij.openapi.vcs.VcsBundle.message; import static com.intellij.openapi.vcs.VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY; -import static com.intellij.openapi.vcs.VcsShowConfirmationOption.Value.SHOW_CONFIRMATION; -import static com.intellij.openapi.vcs.changes.ChangeListManagerImpl.showRemoveEmptyChangeListsProposal; import static com.intellij.openapi.vcs.changes.ChangesUtil.processChangesByVcs; -import static com.intellij.openapi.vcs.changes.ui.CommitHelper.ChangeListsModificationAfterCommit.*; import static com.intellij.util.ArrayUtil.toObjectArray; import static com.intellij.util.ObjectUtils.notNull; import static com.intellij.util.WaitForProgressToShow.runOrInvokeLaterAboveProgress; import static com.intellij.util.containers.ContainerUtil.*; import static com.intellij.util.ui.ConfirmationDialog.requestForConfirmation; import static java.util.Collections.emptyList; -import static java.util.Collections.singleton; import static java.util.stream.Collectors.toList; public class CommitHelper { @@ -292,41 +288,13 @@ public class CommitHelper { } } - enum ChangeListsModificationAfterCommit { - DELETE_LIST, - MOVE_OTHERS, - NOTHING, - ASK_BEFORE_DELETE - } - - public static ChangeListsModificationAfterCommit getRemoveStrategy(VcsShowConfirmationOption.Value removeEmptyInactive) { - if (removeEmptyInactive == DO_ACTION_SILENTLY) return DELETE_LIST; - if (removeEmptyInactive == SHOW_CONFIRMATION) return ASK_BEFORE_DELETE; - return NOTHING; - } - private class CommitProcessor extends GeneralCommitProcessor { @NotNull private LocalHistoryAction myAction = LocalHistoryAction.NULL; - private ChangeListsModificationAfterCommit myPostRefreshModification; private boolean myCommitSuccess; @Nullable private final AbstractVcs myVcs; private CommitProcessor(@Nullable AbstractVcs vcs) { myVcs = vcs; - myPostRefreshModification = NOTHING; - if (myChangeList instanceof LocalChangeList) { - LocalChangeList localList = (LocalChangeList)myChangeList; - boolean containsAll = newHashSet(myIncludedChanges).containsAll(myChangeList.getChanges()); - if (containsAll && !localList.isDefault() && !localList.isReadOnly()) { - myPostRefreshModification = getRemoveStrategy(myConfiguration.REMOVE_EMPTY_INACTIVE_CHANGELISTS); - } - else if (myConfiguration.OFFER_MOVE_TO_ANOTHER_CHANGELIST_ON_PARTIAL_COMMIT && - !containsAll && - localList.isDefault() && - myAllOfDefaultChangeListChangesIncluded) { - myPostRefreshModification = MOVE_OTHERS; - } - } } @Override @@ -382,18 +350,9 @@ public class CommitHelper { clManager.invokeAfterUpdate( () -> { if (myCommitSuccess) { - // do delete/ move of change list if needed - if (myPostRefreshModification == DELETE_LIST || shouldDeleteWithConfirmation()) { - clManager.removeChangeList(myChangeList.getName()); - } - else if (myPostRefreshModification == MOVE_OTHERS) { - ChangelistMoveOfferDialog dialog = new ChangelistMoveOfferDialog(myConfiguration); - if (dialog.showAndGet()) { - Collection changes = clManager.getDefaultChangeList().getChanges(); - MoveChangesToAnotherListAction.askAndMove(myProject, changes, emptyList()); - } - } + updateChangelistAfterRefresh(); } + CommittedChangesCache cache = CommittedChangesCache.getInstance(myProject); // in background since commit must have authorized cache.refreshAllCachesAsync(false, true); @@ -405,11 +364,27 @@ public class CommitHelper { } } - boolean shouldDeleteWithConfirmation() { - // check that changelist exists before asking - return myPostRefreshModification == ASK_BEFORE_DELETE && - ChangeListManager.getInstance(myProject).findChangeList(myChangeList.getName()) != null && - showRemoveEmptyChangeListsProposal(myProject, myConfiguration, singleton(myChangeList)); + private void updateChangelistAfterRefresh() { + if (!(myChangeList instanceof LocalChangeList)) return; + + ChangeListManager clManager = ChangeListManager.getInstance(myProject); + LocalChangeList localList = clManager.findChangeList(myChangeList.getName()); + if (localList == null) return; + + if (!localList.isDefault()) { + clManager.scheduleAutomaticEmptyChangeListDeletion(localList); + } + else { + Collection changes = localList.getChanges(); + if (myConfiguration.OFFER_MOVE_TO_ANOTHER_CHANGELIST_ON_PARTIAL_COMMIT && + !changes.isEmpty() && + myAllOfDefaultChangeListChangesIncluded) { + ChangelistMoveOfferDialog dialog = new ChangelistMoveOfferDialog(myConfiguration); + if (dialog.showAndGet()) { + MoveChangesToAnotherListAction.askAndMove(myProject, changes, emptyList()); + } + } + } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/EditChangelistDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/EditChangelistDialog.java index 2175f5f85df3..353ea00adec2 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/EditChangelistDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/EditChangelistDialog.java @@ -19,6 +19,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.LocalChangeList; @@ -69,20 +70,19 @@ public class EditChangelistDialog extends DialogWrapper { return; } - if (!Comparing.equal(oldName, myPanel.getChangeListName(), true) || !Comparing.equal(oldComment, myPanel.getDescription(), true)) { - final ChangeListManager clManager = ChangeListManager.getInstance(myProject); + final ChangeListManager clManager = ChangeListManager.getInstance(myProject); - final String newName = myPanel.getChangeListName(); - if (! myList.getName().equals(newName)) { - clManager.editName(myList.getName(), newName); - } - final String newDescription = myPanel.getDescription(); - if (! myList.getComment().equals(newDescription)) { - clManager.editComment(myList.getName(), newDescription); - } + final String newDescription = myPanel.getDescription(); + if (!StringUtil.equals(oldComment, newDescription)) { + clManager.editComment(oldName, newDescription); + } + + final String newName = myPanel.getChangeListName(); + if (!StringUtil.equals(oldName, newName)) { + clManager.editName(oldName, newName); } if (!myList.isDefault() && myPanel.getMakeActiveCheckBox().isSelected()) { - ChangeListManager.getInstance(myProject).setDefaultChangeList(myList); + clManager.setDefaultChangeList(newName); } myPanel.changelistCreatedOrChanged(myList); super.doOKAction(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/NewEditChangelistPanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/NewEditChangelistPanel.java index 914901aec04a..16f5bba547c9 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/NewEditChangelistPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/NewEditChangelistPanel.java @@ -30,6 +30,7 @@ import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.*; import com.intellij.util.Consumer; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.text.UniqueNameGenerator; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -62,7 +63,9 @@ public abstract class NewEditChangelistPanel extends JPanel { ComponentWithTextFieldWrapper componentWithTextField = createComponentWithTextField(project); myNameTextField = componentWithTextField.getEditorTextField(); myNameTextField.setOneLineMode(true); - myNameTextField.setText("New changelist"); + String generateUniqueName = UniqueNameGenerator + .generateUniqueName("New changelist", "", "", " (", ")", s -> ChangeListManager.getInstance(myProject).findChangeList(s) == null); + myNameTextField.setText(generateUniqueName); myNameTextField.selectAll(); add(componentWithTextField.myComponent, gb); nameLabel.setLabelFor(myNameTextField); diff --git a/platform/vcs-impl/testSrc/com/intellij/testFramework/vcs/MockChangeListManager.java b/platform/vcs-impl/testSrc/com/intellij/testFramework/vcs/MockChangeListManager.java index 6f89d4acb78e..30a7bc17a8ae 100644 --- a/platform/vcs-impl/testSrc/com/intellij/testFramework/vcs/MockChangeListManager.java +++ b/platform/vcs-impl/testSrc/com/intellij/testFramework/vcs/MockChangeListManager.java @@ -332,6 +332,11 @@ public class MockChangeListManager extends ChangeListManagerEx { return changeList; } + @Override + public void setDefaultChangeList(@NotNull String name) { + throw new UnsupportedOperationException(); + } + @Override public void setDefaultChangeList(@NotNull LocalChangeList list) { myActiveChangeList = list; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/table/VcsLogGraphTable.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/table/VcsLogGraphTable.java index 9d01acf5f4e8..e53965d17462 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/table/VcsLogGraphTable.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/table/VcsLogGraphTable.java @@ -967,7 +967,6 @@ public class VcsLogGraphTable extends TableWithProgress implements DataProvider, @Override public void mouseReleased(@NotNull MouseEvent e) { - if (isOnBorder(e) || isOnRootColumn(e)) return; mouseInputListener.mouseReleased(convertMouseEvent(e)); if (header.getCursor() == Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)) { header.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); @@ -976,32 +975,59 @@ public class VcsLogGraphTable extends TableWithProgress implements DataProvider, @Override public void mouseEntered(@NotNull MouseEvent e) { + mouseInputListener.mouseEntered(convertMouseEvent(e)); } @Override public void mouseExited(@NotNull MouseEvent e) { + mouseInputListener.mouseExited(convertMouseEvent(e)); } @Override public void mouseDragged(@NotNull MouseEvent e) { - if (isOnBorder(e) || isOnRootColumn(e)) return; - int deltaX = Math.abs(e.getX() - myStartXCoordinate); - int deltaY = Math.abs(e.getY() - myStartYCoordinate); - boolean sameColumn = (header.getTable().getColumnModel().getColumn(header.getTable().columnAtPoint(e.getPoint())) == - header.getDraggedColumn()); - // start dragging only if mouse moved horizontally - // or if dragging was already started earlier (it looks weird to stop mid-dragging) - if ((deltaX >= 3 * deltaY && sameColumn) || header.getCursor() == Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR) || - header.getCursor() == Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)) { - mouseInputListener.mouseDragged(convertMouseEvent(e)); - // if I change cursor on mouse pressed, it will change on double-click as well - // and I do not want that - if (header.getDraggedColumn() != null && header.getCursor() == Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)) { + if (!isDraggingEnabled(e)) { + return; + } + + mouseInputListener.mouseDragged(convertMouseEvent(e)); + // if I change cursor on mouse pressed, it will change on double-click as well + // and I do not want that + if (header.getDraggedColumn() != null) { + if (header.getCursor() == Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)) { header.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); } + int draggedColumn = header.getTable().convertColumnIndexToView(header.getDraggedColumn().getModelIndex()); + if (header.getTable().convertColumnIndexToView(ROOT_COLUMN) == draggedColumn + (header.getDraggedDistance() < 0 ? -1 : 1)) { + mouseReleased(e); //cancel dragging to the root column + } } } + private boolean isDraggingEnabled(@NotNull MouseEvent e) { + if (isOnBorder(e) || isOnRootColumn(e)) return false; + // can not check for getDragged/Resized column here since they can be set in mousePressed method + // their presence does not necessarily means something is being dragged or resized + if (header.getCursor() == Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR) || + header.getCursor() == Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)) { + return true; + } + + int deltaX = Math.abs(e.getX() - myStartXCoordinate); + int deltaY = Math.abs(e.getY() - myStartYCoordinate); + Point point = new Point(Math.min(Math.max(e.getX(), 0), header.getTable().getWidth() - 1), e.getY()); + boolean sameColumn; + if (header.getDraggedColumn() == null) { + sameColumn = true; + } + else { + sameColumn = (header.getTable().getColumnModel().getColumn(header.getTable().columnAtPoint(point)) == + header.getDraggedColumn()); + } + // start dragging only if mouse moved horizontally + // or if dragging was already started earlier (it looks weird to stop mid-dragging) + return deltaX >= 3 * deltaY && sameColumn; + } + @Override public void mouseMoved(@NotNull MouseEvent e) { if (isOnBorder(e)) return; diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XFullValueEvaluator.java b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XFullValueEvaluator.java index 6c4f6c9c17fe..d1753cadf620 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XFullValueEvaluator.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XFullValueEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,6 +52,7 @@ public abstract class XFullValueEvaluator { return myShowValuePopup; } + @NotNull public XFullValueEvaluator setShowValuePopup(boolean value) { myShowValuePopup = value; return this; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java index 4efa924cc3d0..7ceb54a568da 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java @@ -206,7 +206,7 @@ public class SideEffectChecker { * @return true if the method has exceptional side effect */ public static boolean mayHaveExceptionalSideEffect(PsiMethod method) { - if (method.getName().startsWith("assert")) { + if (method.getName().startsWith("assert") || method.getName().startsWith("check")) { return true; } return ControlFlowAnalyzer.getMethodContracts(method).stream() diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/ConvertToNestedIfIntention/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/ConvertToNestedIfIntention/after.java.template index 87072e2c61f4..18a7be42b010 100644 --- a/plugins/IntentionPowerPak/src/intentionDescriptions/ConvertToNestedIfIntention/after.java.template +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/ConvertToNestedIfIntention/after.java.template @@ -1,5 +1,5 @@ public class X { - boolean f(boolean a) { + boolean f(boolean a, boolean b) { if (a) { if (b) { return true; diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntConfigurationImpl.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntConfigurationImpl.java index 1e3260c791fa..9e1abc052fb6 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntConfigurationImpl.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntConfigurationImpl.java @@ -118,16 +118,14 @@ public class AntConfigurationImpl extends AntConfigurationBase implements Persis private final Map myModelToBuildFileMap = new HashMap<>(); private final Map myAntFileToContextFileMap = new java.util.HashMap<>(); private final EventDispatcher myEventDispatcher = EventDispatcher.create(AntConfigurationListener.class); - private final AntWorkspaceConfiguration myAntWorkspaceConfiguration; private final StartupManager myStartupManager; - public AntConfigurationImpl(final Project project, final AntWorkspaceConfiguration antWorkspaceConfiguration, final DaemonCodeAnalyzer daemon) { + public AntConfigurationImpl(final Project project, final DaemonCodeAnalyzer daemon) { super(project); getProperties().registerProperty(DEFAULT_ANT, AntReference.EXTERNALIZER); getProperties().rememberKey(INSTANCE); getProperties().rememberKey(DEFAULT_JDK_NAME); INSTANCE.set(getProperties(), this); - myAntWorkspaceConfiguration = antWorkspaceConfiguration; myPsiManager = PsiManager.getInstance(project); myStartupManager = StartupManager.getInstance(project); addAntConfigurationListener(new AntConfigurationListener() { @@ -441,12 +439,12 @@ public class AntConfigurationImpl extends AntConfigurationBase implements Persis @Override public boolean isFilterTargets() { - return myAntWorkspaceConfiguration.FILTER_TARGETS; + return getAntWorkspaceConfiguration().FILTER_TARGETS; } @Override public void setFilterTargets(final boolean value) { - myAntWorkspaceConfiguration.FILTER_TARGETS = value; + getAntWorkspaceConfiguration().FILTER_TARGETS = value; } @Override @@ -530,12 +528,12 @@ public class AntConfigurationImpl extends AntConfigurationBase implements Persis @Override public boolean isAutoScrollToSource() { - return myAntWorkspaceConfiguration.IS_AUTOSCROLL_TO_SOURCE; + return getAntWorkspaceConfiguration().IS_AUTOSCROLL_TO_SOURCE; } @Override public void setAutoScrollToSource(final boolean value) { - myAntWorkspaceConfiguration.IS_AUTOSCROLL_TO_SOURCE = value; + getAntWorkspaceConfiguration().IS_AUTOSCROLL_TO_SOURCE = value; } @Override @@ -677,6 +675,10 @@ public class AntConfigurationImpl extends AntConfigurationBase implements Persis } } + private AntWorkspaceConfiguration getAntWorkspaceConfiguration() { + return AntWorkspaceConfiguration.getInstance(getProject()); + } + private static void collectTargetActions(final AntBuildTarget[] targets, final List> actionList, final AntBuildFile buildFile) { diff --git a/plugins/devkit/src/inspections/ComponentNotRegisteredInspection.java b/plugins/devkit/src/inspections/ComponentNotRegisteredInspection.java index a60f1287bf38..78513d3b4553 100644 --- a/plugins/devkit/src/inspections/ComponentNotRegisteredInspection.java +++ b/plugins/devkit/src/inspections/ComponentNotRegisteredInspection.java @@ -25,7 +25,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.NullableLazyValue; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.MethodReferencesSearch; @@ -41,12 +40,12 @@ import org.jetbrains.idea.devkit.DevKitBundle; import org.jetbrains.idea.devkit.inspections.quickfix.RegisterActionFix; import org.jetbrains.idea.devkit.inspections.quickfix.RegisterComponentFix; import org.jetbrains.idea.devkit.module.PluginModuleType; -import org.jetbrains.idea.devkit.util.ActionType; import org.jetbrains.idea.devkit.util.ComponentType; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import java.util.Map; import java.util.Set; public class ComponentNotRegisteredInspection extends DevKitInspectionBase { @@ -101,15 +100,6 @@ public class ComponentNotRegisteredInspection extends DevKitInspectionBase { GlobalSearchScope scope = checkedClass.getResolveScope(); - final NullableLazyValue registrationType = new NullableLazyValue() { - @Nullable - @Override - protected PsiClass compute() { - final Set types = RegistrationCheckerUtil.getRegistrationTypes(checkedClass, CHECK_ACTIONS, true); - return ContainerUtil.getFirstItem(types); - } - }; - if (CHECK_ACTIONS) { PsiClass actionClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(AnAction.class.getName(), scope); if (actionClass == null) { @@ -120,7 +110,7 @@ public class ComponentNotRegisteredInspection extends DevKitInspectionBase { if (IGNORE_NON_PUBLIC && !checkedClass.hasModifierProperty(PsiModifier.PUBLIC)) { return null; } - if (!isActionRegistered(checkedClass, registrationType.getValue()) && canFix(checkedClass)) { + if (!isActionRegistered(checkedClass) && canFix(checkedClass)) { LocalQuickFix fix = new RegisterActionFix(org.jetbrains.idea.devkit.util.PsiUtil.createPointer(checkedClass)); ProblemDescriptor problem = manager.createProblemDescriptor(classIdentifier, @@ -139,45 +129,50 @@ public class ComponentNotRegisteredInspection extends DevKitInspectionBase { // stop if component class cannot be found (non-devkit module/project) return null; } - if (checkedClass.isInheritor(compClass, true)) { - boolean registeredAsComponent = false; + if (!checkedClass.isInheritor(compClass, true)) { + return null; + } - final PsiClass registrationClass = registrationType.getValue(); - if (registrationClass != null) { - final String qualifiedName = registrationClass.getQualifiedName(); - registeredAsComponent = !ActionType.ACTION.myClassName.equals(qualifiedName) && - !ActionType.GROUP.myClassName.equals(qualifiedName); + for (ComponentType componentType : ComponentType.values()) { + if (!InheritanceUtil.isInheritor(checkedClass, componentType.myClassName)) { + continue; } - if (!registeredAsComponent && canFix(checkedClass)) { - ComponentType type = null; - for (ComponentType componentType : ComponentType.values()) { - if (InheritanceUtil.isInheritor(checkedClass, componentType.myClassName)) { - type = componentType; - break; - } - } - if (type == null) { - return null; - } - - LocalQuickFix fix = new RegisterComponentFix(type, org.jetbrains.idea.devkit.util.PsiUtil.createPointer(checkedClass)); - ProblemDescriptor problem = - manager.createProblemDescriptor(classIdentifier, - DevKitBundle.message("inspections.component.not.registered.message", - DevKitBundle.message(type.myPropertyKey)), - fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly); - return new ProblemDescriptor[]{problem}; + if (findRegistrationType(checkedClass, COMPONENT_TYPE_TO_REGISTRATION_TYPE.get(componentType)) != null) { + return null; } + + if (!canFix(checkedClass)) { + return null; + } + LocalQuickFix fix = new RegisterComponentFix(componentType, org.jetbrains.idea.devkit.util.PsiUtil.createPointer(checkedClass)); + ProblemDescriptor problem = + manager.createProblemDescriptor(classIdentifier, + DevKitBundle.message("inspections.component.not.registered.message", + DevKitBundle.message(componentType.myPropertyKey)), + fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly); + return new ProblemDescriptor[]{problem}; } } return null; } - private static boolean isActionRegistered(PsiClass actionClass, PsiClass registrationType) { + private static final Map COMPONENT_TYPE_TO_REGISTRATION_TYPE = + ContainerUtil.immutableMapBuilder() + .put(ComponentType.APPLICATION, RegistrationCheckerUtil.RegistrationType.APPLICATION_COMPONENT) + .put(ComponentType.PROJECT, RegistrationCheckerUtil.RegistrationType.PROJECT_COMPONENT) + .put(ComponentType.MODULE, RegistrationCheckerUtil.RegistrationType.MODULE_COMPONENT) + .build(); + + private static PsiClass findRegistrationType(@Nullable PsiClass checkedClass, RegistrationCheckerUtil.RegistrationType type) { + final Set types = RegistrationCheckerUtil.getRegistrationTypes(checkedClass, type); + return ContainerUtil.getFirstItem(types); + } + + private static boolean isActionRegistered(PsiClass actionClass) { + final PsiClass registrationType = findRegistrationType(actionClass, RegistrationCheckerUtil.RegistrationType.ACTION); if (registrationType != null) { - if (ActionType.ACTION.myClassName.equals(registrationType.getQualifiedName())) return true; - if (ActionType.GROUP.myClassName.equals(registrationType.getQualifiedName())) return true; + return true; } // search code usages: 1) own CTOR calls 2) usage via "new ActionClass()" diff --git a/plugins/devkit/src/inspections/RegistrationCheckerUtil.java b/plugins/devkit/src/inspections/RegistrationCheckerUtil.java index 08435b07cb5b..17d8701ae527 100644 --- a/plugins/devkit/src/inspections/RegistrationCheckerUtil.java +++ b/plugins/devkit/src/inspections/RegistrationCheckerUtil.java @@ -16,7 +16,6 @@ package org.jetbrains.idea.devkit.inspections; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.paths.PathReference; import com.intellij.openapi.project.Project; @@ -43,8 +42,17 @@ import java.util.Set; class RegistrationCheckerUtil { + enum RegistrationType { + ALL, + ALL_COMPONENTS, + APPLICATION_COMPONENT, + PROJECT_COMPONENT, + MODULE_COMPONENT, + ACTION + } + @Nullable - static Set getRegistrationTypes(PsiClass psiClass, boolean includeActions, boolean stopOnFirst) { + static Set getRegistrationTypes(PsiClass psiClass, RegistrationType registrationType) { final Project project = psiClass.getProject(); final PsiFile psiFile = psiClass.getContainingFile(); @@ -53,42 +61,31 @@ class RegistrationCheckerUtil { final VirtualFile virtualFile = psiFile.getVirtualFile(); if (virtualFile == null) return null; final Module module = ModuleUtilCore.findModuleForFile(virtualFile, project); - if (module == null) return null; final boolean isIdeaProject = PsiUtil.isIdeaProject(project); - if (PluginModuleType.isOfType(module) || - PsiUtil.isPluginModule(module)) { - final Set pluginModuleResults = checkModule(module, psiClass, includeActions, stopOnFirst); - if (!isIdeaProject && pluginModuleResults != null) { - return pluginModuleResults; - } + final Set pluginModuleResults = checkModule(module, isIdeaProject, psiClass, registrationType); + if (pluginModuleResults != null) { + return pluginModuleResults; } final List candidateModules = PluginModuleType.getCandidateModules(module); candidateModules.remove(module); // already checked for (Module m : candidateModules) { - Set types = checkModule(m, psiClass, includeActions, stopOnFirst); + Set types = checkModule(m, isIdeaProject, psiClass, registrationType); if (types != null) return types; } - // fallback in IJ project: all modules - if (isIdeaProject) { - for (Module m : ModuleManager.getInstance(module.getProject()).getModules()) { - if (candidateModules.contains(m)) continue; - Set types = checkModule(m, psiClass, includeActions, stopOnFirst); - if (types != null) { - return types; - } - } - } return null; } @Nullable - private static Set checkModule(Module module, PsiClass psiClass, boolean includeActions, boolean stopOnFirst) { - List> pluginXmlCandidates = findPluginXmlFilesForModule(module); + private static Set checkModule(Module module, + boolean isIdeaProject, + PsiClass psiClass, + RegistrationType registrationType) { + List> pluginXmlCandidates = findPluginXmlFilesForModule(module, isIdeaProject); if (pluginXmlCandidates.isEmpty()) return null; final String qualifiedName = psiClass.getQualifiedName(); @@ -96,13 +93,13 @@ class RegistrationCheckerUtil { return null; } - final RegistrationTypeFinder finder = new RegistrationTypeFinder(psiClass, stopOnFirst); - - final List candidateXmlFiles = ContainerUtil.map(pluginXmlCandidates, element -> element.getFile()); + final RegistrationTypeFinder finder = new RegistrationTypeFinder(psiClass); for (DomFileElement pluginXml : pluginXmlCandidates) { // "main" plugin.xml - if (!processPluginXml(pluginXml, finder, includeActions)) return finder.getTypes(); + if (!processPluginXml(pluginXml, finder, registrationType)) return finder.getTypes(); + + if (isIdeaProject) continue; // pluginXmlCandidates == all candidates in module // plugin.xml files for (Dependency dependency : pluginXml.getRootElement().getDependencies()) { @@ -114,11 +111,10 @@ class RegistrationCheckerUtil { final PsiElement resolve = configFile.resolve(); if (!(resolve instanceof XmlFile)) continue; final XmlFile depPluginXml = (XmlFile)resolve; - if (candidateXmlFiles.contains(depPluginXml)) continue; // already processed final DomFileElement dependentIdeaPlugin = DescriptorUtil.getIdeaPlugin(depPluginXml); if (dependentIdeaPlugin != null) { - if (!processPluginXml(dependentIdeaPlugin, finder, includeActions)) return finder.getTypes(); + if (!processPluginXml(dependentIdeaPlugin, finder, registrationType)) return finder.getTypes(); } } } @@ -128,10 +124,7 @@ class RegistrationCheckerUtil { } @NotNull - private static List> findPluginXmlFilesForModule(Module module) { - final Project project = module.getProject(); - final boolean isIdeaProject = PsiUtil.isIdeaProject(project); - + private static List> findPluginXmlFilesForModule(Module module, boolean isIdeaProject) { XmlFile pluginXml = PluginModuleType.getPluginXml(module); if (pluginXml != null && !isIdeaProject) { return Collections.singletonList(DescriptorUtil.getIdeaPlugin(pluginXml)); @@ -141,29 +134,40 @@ class RegistrationCheckerUtil { return Collections.emptyList(); } - return DomService.getInstance().getFileElements(IdeaPlugin.class, project, + return DomService.getInstance().getFileElements(IdeaPlugin.class, module.getProject(), GlobalSearchScope.moduleRuntimeScope(module, false)); } private static boolean processPluginXml(DomFileElement pluginXml, RegistrationTypeFinder finder, - boolean includeActions) { + RegistrationType registrationType) { final IdeaPlugin rootElement = pluginXml.getRootElement(); - if (!ContainerUtil.process(rootElement.getApplicationComponents(), components -> - finder.processComponents(ComponentType.APPLICATION, components.getComponents()))) { - return false; - } - if (!ContainerUtil.process(rootElement.getProjectComponents(), components -> - finder.processComponents(ComponentType.PROJECT, components.getComponents()))) { - return false; - } - if (!ContainerUtil.process(rootElement.getModuleComponents(), components -> - finder.processComponents(ComponentType.MODULE, components.getComponents()))) { - return false; + final boolean findAll = registrationType == RegistrationType.ALL; + final boolean allComponents = findAll || registrationType == RegistrationType.ALL_COMPONENTS; + + if (allComponents || registrationType == RegistrationType.APPLICATION_COMPONENT) { + if (!ContainerUtil.process(rootElement.getApplicationComponents(), components -> + finder.processComponents(ComponentType.APPLICATION, components.getComponents()))) { + return false; + } } - if (includeActions) { + if (allComponents || registrationType == RegistrationType.PROJECT_COMPONENT) { + if (!ContainerUtil.process(rootElement.getProjectComponents(), components -> + finder.processComponents(ComponentType.PROJECT, components.getComponents()))) { + return false; + } + } + + if (allComponents || registrationType == RegistrationType.MODULE_COMPONENT) { + if (!ContainerUtil.process(rootElement.getModuleComponents(), components -> + finder.processComponents(ComponentType.MODULE, components.getComponents()))) { + return false; + } + } + + if (findAll || registrationType == RegistrationType.ACTION) { if (!ContainerUtil.process(rootElement.getActions(), actions -> finder.processActions(actions))) { return false; @@ -175,13 +179,11 @@ class RegistrationCheckerUtil { private static class RegistrationTypeFinder { private final PsiClass myPsiClass; - private final boolean myStopOnFirst; private final Set myTypes = ContainerUtil.newIdentityTroveSet(1); - private RegistrationTypeFinder(PsiClass psiClass, boolean stopOnFirst) { + private RegistrationTypeFinder(PsiClass psiClass) { myPsiClass = psiClass; - myStopOnFirst = stopOnFirst; } private boolean processComponents(ComponentType type, List components) { @@ -211,7 +213,7 @@ class RegistrationCheckerUtil { private boolean processGroup(Group group) { final GenericAttributeValue groupClazz = group.getClazz(); - if (DomUtil.hasXml(groupClazz) && myPsiClass.isEquivalentTo(groupClazz.getValue())) { + if (matchesClass(groupClazz)) { if (addType(ActionType.GROUP.myClassName, group)) return false; } @@ -225,16 +227,28 @@ class RegistrationCheckerUtil { } private boolean processAction(Action action) { - if (myPsiClass.isEquivalentTo(action.getClazz().getValue())) { + if (matchesClass(action.getClazz())) { if (addType(ActionType.ACTION.myClassName, action)) return false; } return true; } + private boolean matchesClass(GenericAttributeValue attributeValue) { + if (!DomUtil.hasXml(attributeValue)) return false; + + final String stringValue = attributeValue.getStringValue(); + if (stringValue == null) return false; + + // perform cheap String comparison first + final String clazzName = stringValue.replace('$', '.'); + return clazzName.equals(myPsiClass.getQualifiedName()) && + myPsiClass.isEquivalentTo(attributeValue.getValue()); + } + private boolean addType(String fqn, DomElement context) { final PsiClass psiClass = DomJavaUtil.findClass(fqn, context); ContainerUtil.addIfNotNull(myTypes, psiClass); - return psiClass != null && myStopOnFirst; + return psiClass != null; } private Set getTypes() { diff --git a/plugins/devkit/src/inspections/RegistrationProblemsInspection.java b/plugins/devkit/src/inspections/RegistrationProblemsInspection.java index d30a0ee0526f..aba52942d4dc 100644 --- a/plugins/devkit/src/inspections/RegistrationProblemsInspection.java +++ b/plugins/devkit/src/inspections/RegistrationProblemsInspection.java @@ -115,7 +115,9 @@ public class RegistrationProblemsInspection extends DevKitInspectionBase { nameIdentifier != null && checkedClass.getQualifiedName() != null && checkedClass.getContainingFile().getVirtualFile() != null) { - final Set componentClasses = RegistrationCheckerUtil.getRegistrationTypes(checkedClass, CHECK_ACTIONS, false); + final RegistrationCheckerUtil.RegistrationType registrationType = + CHECK_ACTIONS ? RegistrationCheckerUtil.RegistrationType.ALL : RegistrationCheckerUtil.RegistrationType.ALL_COMPONENTS; + final Set componentClasses = RegistrationCheckerUtil.getRegistrationTypes(checkedClass, registrationType); if (componentClasses != null && !componentClasses.isEmpty()) { List problems = new SmartList<>(); diff --git a/plugins/git4idea/src/git4idea/history/GitFileHistory.java b/plugins/git4idea/src/git4idea/history/GitFileHistory.java index 768d671b8be7..7da3401f8155 100644 --- a/plugins/git4idea/src/git4idea/history/GitFileHistory.java +++ b/plugins/git4idea/src/git4idea/history/GitFileHistory.java @@ -118,7 +118,9 @@ public class GitFileHistory { } try { - Pair firstCommitParentAndPath = getFirstCommitParentAndPathIfRename(recordConsumer.getFirstCommit(), currentPath); + String firstCommit = recordConsumer.getFirstCommit(); + if (firstCommit == null) return; + Pair firstCommitParentAndPath = getFirstCommitParentAndPathIfRename(firstCommit, currentPath); if (firstCommitParentAndPath == null) { return; } @@ -448,7 +450,7 @@ public class GitFileHistory { return myCurrentPath.get(); } - @NotNull + @Nullable public String getFirstCommit() { return myFirstCommit.get(); } diff --git a/plugins/git4idea/src/git4idea/history/GitLogUtil.java b/plugins/git4idea/src/git4idea/history/GitLogUtil.java index 6d0176541ad3..a9629d1de6dd 100644 --- a/plugins/git4idea/src/git4idea/history/GitLogUtil.java +++ b/plugins/git4idea/src/git4idea/history/GitLogUtil.java @@ -90,6 +90,7 @@ public class GitLogUtil { for (String parent : record.getParentsHashes()) { parents.add(HashImpl.build(parent)); } + record.setUsedHandler(h); return factory.createShortDetails(HashImpl.build(record.getHash()), parents, record.getCommitTime(), root, record.getSubject(), record.getAuthorName(), record.getAuthorEmail(), record.getCommitterName(), record.getCommitterEmail(), @@ -121,6 +122,7 @@ public class GitLogUtil { List records = parser.parse(output); for (GitLogRecord record : records) { if (record == null) continue; + record.setUsedHandler(handler); Hash hash = HashImpl.build(record.getHash()); List parents = getParentHashes(factory, record); @@ -286,6 +288,7 @@ public class GitLogUtil { try { GitLogRecord record = parser.parseOneRecord(output); if (record != null) { + record.setUsedHandler(handler); converter.consume(record); } } diff --git a/plugins/git4idea/src/git4idea/rebase/GitRebaseSpec.java b/plugins/git4idea/src/git4idea/rebase/GitRebaseSpec.java index 5762dae75dcc..df44e33afa3e 100644 --- a/plugins/git4idea/src/git4idea/rebase/GitRebaseSpec.java +++ b/plugins/git4idea/src/git4idea/rebase/GitRebaseSpec.java @@ -21,6 +21,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.VcsBundle; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.Hash; import git4idea.GitLocalBranch; @@ -156,7 +157,7 @@ public class GitRebaseSpec { @NotNull private static GitStashChangesSaver newSaver(@NotNull Project project, @NotNull ProgressIndicator indicator) { Git git = Git.getInstance(); - return new GitStashChangesSaver(project, git, indicator, "Uncommitted changes before rebase"); + return new GitStashChangesSaver(project, git, indicator, VcsBundle.message("stash.changes.message", "rebase")); } @NotNull diff --git a/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java b/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java index 9f6e1103cbce..8af96cbc1727 100644 --- a/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java +++ b/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java @@ -33,6 +33,8 @@ import org.jetbrains.annotations.NotNull; import java.util.*; +import static com.intellij.openapi.vcs.changes.ChangeListUtil.createSystemShelvedChangeListName; + public class GitShelveChangesSaver extends GitChangesSaver { private static final Logger LOG = Logger.getInstance(GitShelveChangesSaver.class); @@ -66,9 +68,10 @@ public class GitShelveChangesSaver extends GitChangesSaver { for (Collection changeCollection : map.values()) { changes.addAll(changeCollection); } - if (! changes.isEmpty()) { - final ShelvedChangeList list = GitShelveUtils.shelveChanges(myProject, myShelveManager, changes, - myStashMessage + " [" + entry.getKey() + "]", exceptions, false, true); + if (!changes.isEmpty()) { + final ShelvedChangeList list = GitShelveUtils + .shelveChanges(myProject, myShelveManager, changes, createSystemShelvedChangeListName(myStashMessage, entry.getKey()), exceptions, + false, true); myShelvedLists.put(entry.getKey(), list); } } diff --git a/plugins/git4idea/src/git4idea/util/GitPreservingProcess.java b/plugins/git4idea/src/git4idea/util/GitPreservingProcess.java index 39172a698ec7..56e03cbb758a 100644 --- a/plugins/git4idea/src/git4idea/util/GitPreservingProcess.java +++ b/plugins/git4idea/src/git4idea/util/GitPreservingProcess.java @@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Clock; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.VcsNotifier; import com.intellij.openapi.vcs.history.VcsRevisionNumber; @@ -74,8 +75,8 @@ public class GitPreservingProcess { myDestinationName = destinationName; myProgressIndicator = indicator; myOperation = operation; - myStashMessage = String.format("Uncommitted changes before %s at %s", StringUtil.capitalize(myOperationTitle), - DateFormatUtil.formatDateTime(Clock.getTime())); + myStashMessage = VcsBundle.message("stash.changes.message", StringUtil.capitalize(myOperationTitle)) + + " at " +DateFormatUtil.formatDateTime(Clock.getTime()); mySaver = configureSaver(saveMethod); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleManager.java index c370f7975290..c4837145aeb0 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -361,9 +361,7 @@ public class GradleManager String projectPath = taskExecutionSettings.getExternalProjectPath(); if (StringUtil.isEmpty(projectPath)) return null; - GradleProjectSettings projectSettings = - - getSettingsProvider().fun(project).getLinkedProjectSettings(projectPath); + GradleProjectSettings projectSettings = getSettingsProvider().fun(project).getLinkedProjectSettings(projectPath); if (projectSettings == null) return null; if (!projectSettings.isResolveModulePerSourceSet()) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleModuleBuilder.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleModuleBuilder.java index 839cfa980e7a..e47f2f58440f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleModuleBuilder.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleModuleBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.model.project.ProjectId; import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl; import com.intellij.openapi.externalSystem.service.project.wizard.AbstractExternalModuleBuilder; import com.intellij.openapi.externalSystem.service.project.wizard.ExternalModuleSettingsStep; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; @@ -458,4 +459,15 @@ public class GradleModuleBuilder extends AbstractExternalModuleBuilder { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectCompositeSelectorDialog.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectCompositeSelectorDialog.java index 4b1f83dea1dd..0c0d5dc19665 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectCompositeSelectorDialog.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectCompositeSelectorDialog.java @@ -70,7 +70,7 @@ public class GradleProjectCompositeSelectorDialog extends DialogWrapper { myExternalSystemUiAware = ExternalSystemUiUtil.getUiAware(GradleConstants.SYSTEM_ID); myTree = createTree(); - setTitle(String.format("%s Project Build Composite", GradleConstants.SYSTEM_ID.getReadableName())); + setTitle("Composite Build Configuration"); init(); } @@ -121,7 +121,7 @@ public class GradleProjectCompositeSelectorDialog extends DialogWrapper { private CheckboxTree createTree() { final CheckedTreeNode root = new CheckedTreeNode(); if (myCompositeRootSettings != null) { - List nodes = ContainerUtil.newArrayList(); + List nodes = ContainerUtil.newArrayList(); for (GradleProjectSettings projectSettings : GradleSettings.getInstance(myProject).getLinkedProjectsSettings()) { if (projectSettings == myCompositeRootSettings) continue; if (projectSettings.getCompositeBuild() != null && @@ -140,6 +140,8 @@ public class GradleProjectCompositeSelectorDialog extends DialogWrapper { nodes.add(treeNode); } + ContainerUtil.sort(nodes, (o1, o2) -> + StringUtil.naturalCompare((String)((Pair)o1.getUserObject()).first, (String)((Pair)o2.getUserObject()).first)); TreeUtil.addChildrenTo(root, nodes); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyDirectInheritorsSearcher.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyDirectInheritorsSearcher.java index d8046317e671..6980e4c583bf 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyDirectInheritorsSearcher.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyDirectInheritorsSearcher.java @@ -21,6 +21,7 @@ import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.impl.search.StubHierarchyInheritorSearcher; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.GlobalSearchScopeUtil; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.DirectClassInheritorsSearch; import com.intellij.psi.stubs.StubIndex; @@ -71,23 +72,19 @@ public class GroovyDirectInheritorsSearcher implements QueryExecutor candidates = DumbService.getInstance(project).runReadActionInSmartMode(() -> { - if (!clazz.isValid()) return Collections.emptyList(); - GlobalSearchScope restrictedScope = StubHierarchyInheritorSearcher.restrictScope((GlobalSearchScope)scope); - return getDerivingClassCandidates(clazz, restrictedScope, queryParameters.includeAnonymous()); - }); - for (final PsiClass candidate : candidates) { - if (!queryParameters.isCheckInheritance() || isInheritor(clazz, candidate, project)) { - if (!consumer.process(candidate)) { - return false; - } + GlobalSearchScope globalSearchScope = GlobalSearchScopeUtil.toGlobalSearchScope(scope, project); + final List candidates = DumbService.getInstance(project).runReadActionInSmartMode(() -> { + if (!clazz.isValid()) return Collections.emptyList(); + GlobalSearchScope restrictedScope = StubHierarchyInheritorSearcher.restrictScope(globalSearchScope); + return getDerivingClassCandidates(clazz, restrictedScope, queryParameters.includeAnonymous()); + }); + for (final PsiClass candidate : candidates) { + if (!queryParameters.isCheckInheritance() || isInheritor(clazz, candidate, project)) { + if (!consumer.process(candidate)) { + return false; } } - - return true; } - return true; } diff --git a/plugins/junit/src/com/intellij/execution/junit/TestClassConfigurationProducer.java b/plugins/junit/src/com/intellij/execution/junit/TestClassConfigurationProducer.java index 7356713ead28..277606f50fd5 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestClassConfigurationProducer.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestClassConfigurationProducer.java @@ -17,8 +17,9 @@ package com.intellij.execution.junit; import com.intellij.execution.testframework.AbstractInClassConfigurationProducer; +//to be deleted in 2018 @Deprecated -public class TestClassConfigurationProducer extends AbstractInClassConfigurationProducer { +public class TestClassConfigurationProducer extends AbstractInClassConfigurationProducer { public TestClassConfigurationProducer() { super(JUnitConfigurationType.getInstance()); } diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java b/plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java index c6a3dde66362..eda64f393577 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java @@ -17,8 +17,9 @@ package com.intellij.execution.junit; import com.intellij.execution.testframework.AbstractInClassConfigurationProducer; +//to be delete in 2018 @Deprecated -public class TestMethodConfigurationProducer extends AbstractInClassConfigurationProducer { +public class TestMethodConfigurationProducer extends AbstractInClassConfigurationProducer { public TestMethodConfigurationProducer() { super(JUnitConfigurationType.getInstance()); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java index 8a88032f8a5f..2878e629f779 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java @@ -40,6 +40,7 @@ import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.roots.impl.ModuleRootManagerImpl; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; @@ -563,6 +564,8 @@ public class MavenProjectsManager extends MavenSimpleProjectComponent for (Module m : modules) { if (m.isDisposed()) continue; ExternalSystemModulePropertyManager.getInstance(m).setMavenized(mavenized); + // force re-save (since can be stored externally) + ((ModuleRootManagerImpl)ModuleRootManager.getInstance(m)).stateChanged(); } } diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java index 2b1b5b0b19dd..3152d1b2464a 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,8 @@ import com.intellij.lang.properties.parsing.PropertiesElementTypes; import com.intellij.lang.properties.psi.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.FileViewProvider; @@ -192,12 +194,19 @@ public class PropertiesFileImpl extends PsiFileBase implements PropertiesFile { } private Stream propertiesByKey(@NotNull String key) { - VirtualFile file = getVirtualFile(); - if (file != null && ProjectFileIndex.getInstance(getProject()).isInContent(file)) { + if (shouldReadIndex()) { return PropertyKeyIndex.getInstance().get(key, getProject(), GlobalSearchScope.fileScope(this)).stream(); - } else { + } + else { // see PropertiesElementFactory.createPropertiesFile(Project, Properties, String) return getProperties().stream().filter(p -> key.equals(p.getUnescapedKey())); } } + + private boolean shouldReadIndex() { + Project project = getProject(); + if (DumbService.getInstance(project).isDumb()) return false; + VirtualFile file = getVirtualFile(); + return file != null && ProjectFileIndex.getInstance(project).isInContent(file); + } } diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundlePropertiesUpdateManager.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundlePropertiesUpdateManager.java index 45e1aec1018a..5b260a45b273 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundlePropertiesUpdateManager.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundlePropertiesUpdateManager.java @@ -234,6 +234,7 @@ public class ResourceBundlePropertiesUpdateManager { myKeys = new ArrayList<>(properties.size()); myKeyIndices = new FactoryMap() { + @NotNull @Override protected Map createMap() { return new THashMap<>(properties.size()); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties index 832c49f71828..16f2a17ca55f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties @@ -484,7 +484,7 @@ repository.browser.add.location.title=New Repository Location repository.browser.details.action=Show/Hide Details repository.browser.refresh.action=Refresh selected tree node repository.browser.add.location.menu.item=_Repository Location... -repository.browser.edit.location.menu.item= Edit Location _Url... +repository.browser.edit.location.menu.item= Edit Location _URL... repository.browser.discard.location.action=Discard _Location repository.browser.discard.location.prompt=Would you like to discard the location ''{0}''? repository.browser.discard.location.title=Discard Location @@ -634,7 +634,7 @@ undo.integrate.to.branch=Undo Integrate To Branch... undo.integrate.to.branch.description=Removes changes done in revision from branch undo.integrate.to.branch.dialog.title=Undo Integrate To Branch merge.source.details.title=Merge source details for {0} [{1}] -repository.browser.edit.location.dialog.title= Edit Location Url +repository.browser.edit.location.dialog.title= Edit Location URL loading.default.branches.configuration.text=Loading default branches configuration... loading.data.for.root.text=Loading data for {0} action.Subversion.TogglePropertiesDiff.text=Show properties diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/LocalChangesPromptTask.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/LocalChangesPromptTask.java index 66de4ef71e16..c5b6f6875e8c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/LocalChangesPromptTask.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/LocalChangesPromptTask.java @@ -21,6 +21,7 @@ import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.changes.ChangeListUtil; import com.intellij.openapi.vcs.changes.LocalChangeList; import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; import com.intellij.util.FilePathByPathComparator; @@ -39,6 +40,7 @@ import java.util.Set; import static com.intellij.openapi.application.ApplicationManager.getApplication; import static com.intellij.openapi.util.Conditions.alwaysTrue; import static com.intellij.openapi.util.text.StringUtil.isEmptyOrSpaces; +import static com.intellij.openapi.vcs.VcsBundle.message; import static com.intellij.openapi.vcs.changes.ChangesUtil.*; import static com.intellij.util.containers.ContainerUtil.sorted; import static java.util.stream.Collectors.toSet; @@ -108,7 +110,8 @@ public class LocalChangesPromptTask extends BaseMergeTask { ShelveChangesManager shelveManager = ShelveChangesManager.getInstance(myMergeContext.getProject()); for (Map.Entry> entry : intersection.getChangesByLists().entrySet()) { - String shelfName = intersection.getComment(entry.getKey()) + " (auto shelve before merge)"; + String shelfName = ChangeListUtil + .createSystemShelvedChangeListName(message("stash.changes.message", "merge"), intersection.getComment(entry.getKey())); shelveManager.shelveChanges(entry.getValue(), shelfName, true, true); } diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/AbstractTestNGInClassConfigurationProducer.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/AbstractTestNGInClassConfigurationProducer.java new file mode 100644 index 000000000000..a41412ca4a6b --- /dev/null +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/AbstractTestNGInClassConfigurationProducer.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.theoryinpractice.testng.configuration; + +import com.intellij.execution.configurations.ConfigurationType; + +//to be delete in 2018 +@Deprecated +public class AbstractTestNGInClassConfigurationProducer extends TestNGInClassConfigurationProducer { + @Deprecated + public AbstractTestNGInClassConfigurationProducer() { + } + + @Deprecated + public AbstractTestNGInClassConfigurationProducer(ConfigurationType configurationType) { + super(configurationType); + } +} diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGInClassConfigurationProducer.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGInClassConfigurationProducer.java index 16a785f99aff..d54f1a69d128 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGInClassConfigurationProducer.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGInClassConfigurationProducer.java @@ -26,7 +26,11 @@ import org.jetbrains.annotations.NotNull; public class TestNGInClassConfigurationProducer extends TestNGConfigurationProducer { private TestNGInClassConfigurationProducerDelegate myDelegate = new TestNGInClassConfigurationProducerDelegate(TestNGConfigurationType.getInstance()); protected TestNGInClassConfigurationProducer() { - super(TestNGConfigurationType.getInstance()); + this(TestNGConfigurationType.getInstance()); + } + + protected TestNGInClassConfigurationProducer(final ConfigurationType configurationType) { + super(configurationType); } @Override diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java index b08cb49066eb..11d78532fe80 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java @@ -1,7 +1,6 @@ package com.jetbrains.edu.coursecreator; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileEvent; @@ -77,18 +76,17 @@ public class CCVirtualFileListener implements VirtualFileListener { return; } - Project project = ProjectUtil.guessProjectForFile(removedFile); - if (project == null) { + if (myProject == null) { return; } - if (project.getBasePath() !=null && !FileUtil.isAncestor(project.getBasePath(), removedFile.getPath(), true)) { + if (myProject.getBasePath() !=null && !FileUtil.isAncestor(myProject.getBasePath(), removedFile.getPath(), true)) { return; } - Course course = StudyTaskManager.getInstance(project).getCourse(); + Course course = StudyTaskManager.getInstance(myProject).getCourse(); if (course == null) { return; } - final TaskFile taskFile = StudyUtils.getTaskFile(project, removedFile); + final TaskFile taskFile = StudyUtils.getTaskFile(myProject, removedFile); if (taskFile != null) { deleteTaskFile(removedFile, taskFile); return; @@ -97,7 +95,7 @@ public class CCVirtualFileListener implements VirtualFileListener { deleteTask(course, removedFile); } if (removedFile.getName().contains(EduNames.LESSON)) { - deleteLesson(course, removedFile, project); + deleteLesson(course, removedFile, myProject); } } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/StudyTaskManager.java b/python/educational-core/src/com/jetbrains/edu/learning/StudyTaskManager.java index 5014a322c1d0..810c24113f9f 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/StudyTaskManager.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/StudyTaskManager.java @@ -4,10 +4,7 @@ import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.fileTemplates.FileTemplateUtil; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.PersistentStateComponent; -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.components.State; -import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; @@ -41,7 +38,7 @@ import static com.jetbrains.edu.learning.StudySerializationUtils.Xml.REMOTE_COUR * about study in context of current project */ -@State(name = "StudySettings", storages = @Storage("study_project.xml")) +@State(name = "StudySettings", storages = @Storage(value = "study_project.xml", roamingType = RoamingType.DISABLED)) public class StudyTaskManager implements PersistentStateComponent, DumbAware { private static final Logger LOG = Logger.getInstance(StudyTaskManager.class); public static final int CURRENT_VERSION = 6; diff --git a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyLanguageLevelInspection.kt b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyLanguageLevelInspection.kt index f89f717f7f81..474a169c9f49 100644 --- a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyLanguageLevelInspection.kt +++ b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyLanguageLevelInspection.kt @@ -8,7 +8,6 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.module.ModuleUtilCore import com.intellij.openapi.options.ShowSettingsUtil import com.intellij.openapi.project.Project -import com.intellij.openapi.project.guessProjectForContentFile import com.intellij.psi.PsiElementVisitor import com.intellij.psi.util.PsiUtilCore import com.jetbrains.edu.learning.courseFormat.Course @@ -42,7 +41,7 @@ class PyStudyLanguageLevelInspection : PyInspection() { val sdk = PythonSdkType.findPythonSdk(module) if (sdk != null) { val projectLanguageLevel = PythonSdkType.getLanguageLevelForSdk(sdk) - val project = guessProjectForContentFile(node.virtualFile) ?: return + val project = node.project val course = StudyTaskManager.getInstance(project).course ?: return checkIfLanguageLevelSupported(course, projectLanguageLevel, node) } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java index 35e0d84f33d7..7b1f9aab1992 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java @@ -14,6 +14,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.InputValidator; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.*; @@ -174,7 +175,18 @@ public final class IpnbConnectionManager implements ProjectComponent, Disposable private static Pair askForUrlAndToken() { final String urlToken = Messages.showInputDialog("Please, enter your Jupyter Notebook URL and authentication token", - "Jupyter Notebook", null, "http://localhost:8888/?token=", null); + "Jupyter Notebook", null, "http://localhost:8888/?token=", + new InputValidator() { + @Override + public boolean checkInput(String inputString) { + return !inputString.endsWith("?token="); + } + + @Override + public boolean canClose(String inputString) { + return true; + } + }); if (!StringUtil.isEmptyOrSpaces(urlToken)) { final String trimmed = urlToken.trim(); final List strings = StringUtil.split(trimmed, "?token=", true); diff --git a/python/psi-api/src/com/jetbrains/python/PyNames.java b/python/psi-api/src/com/jetbrains/python/PyNames.java index 57487a9e985e..5c84eec859de 100644 --- a/python/psi-api/src/com/jetbrains/python/PyNames.java +++ b/python/psi-api/src/com/jetbrains/python/PyNames.java @@ -64,6 +64,10 @@ public class PyNames { */ public static final String TYPE_TIME = "datetime.time"; + public static final String TYPE_BYTES = "bytes"; + + public static final String TYPE_BYTEARRAY = "bytearray"; + public static final String TYPE_ENUM = "enum.Enum"; private PyNames() { @@ -217,6 +221,8 @@ public class PyNames { public static final String UNNAMED_ELEMENT = ""; + public static final String UNDERSCORE = "_"; + /** * Contains all known predefined names of "__foo__" form. */ diff --git a/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java b/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java index 7f9d3946aeee..7f4f1d93f58d 100644 --- a/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java @@ -78,6 +78,7 @@ public class PyRedeclarationInspection extends PyInspection { @Override public void visitPyTargetExpression(final PyTargetExpression node) { + if (PyNames.UNDERSCORE.equals(node.getText())) return; final ScopeOwner owner = ScopeUtil.getScopeOwner(node); if (owner instanceof PyFile || owner instanceof PyClass) { processElement(node); diff --git a/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java b/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java index 795aab4b5a23..80d925065f37 100644 --- a/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.Scope; @@ -92,7 +93,7 @@ public class PyShadowingNamesInspection extends PyInspection { if (name != null) { final PsiElement identifier = element.getNameIdentifier(); final PsiElement problemElement = identifier != null ? identifier : element; - if ("_".equals(name)) { + if (PyNames.UNDERSCORE.equals(name) || name.startsWith(PyNames.UNDERSCORE) && element instanceof PyParameter) { return; } if (owner != null) { diff --git a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java index 28c16ce42d42..98b86605cea5 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java +++ b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java @@ -157,7 +157,11 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { final String name = readWriteInstruction.getName(); // Ignore empty, wildcards, global and nonlocal names final Scope scope = ControlFlowCache.getScope(owner); - if (name == null || "_".equals(name) || scope.isGlobal(name) || scope.isNonlocal(name)) { + if (name == null || PyNames.UNDERSCORE.equals(name) || scope.isGlobal(name) || scope.isNonlocal(name)) { + continue; + } + // Ignore underscore-prefixed parameters + if (name.startsWith(PyNames.UNDERSCORE) && element instanceof PyParameter) { continue; } // Ignore elements out of scope diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java index d2c1c45fab48..cd15397fe2e7 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java @@ -41,8 +41,10 @@ import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.net.HttpConfigurable; import com.jetbrains.python.PythonHelpersLocator; import com.jetbrains.python.psi.LanguageLevel; +import com.jetbrains.python.run.CommandLinePatcher; import com.jetbrains.python.sdk.PythonEnvUtil; import com.jetbrains.python.sdk.PythonSdkType; +import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -471,6 +473,10 @@ public class PyPackageManagerImpl extends PyPackageManager { PythonEnvUtil.setPythonUnbuffered(environment); PythonEnvUtil.setPythonDontWriteBytecode(environment); PythonEnvUtil.resetHomePathChanges(homePath, environment); + final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(mySdk); + if (flavor != null && flavor.commandLinePatcher() != null) { + flavor.commandLinePatcher().patchCommandLine(commandLine); + } final Process process; if (useSudo) { process = ExecUtil.sudo(commandLine, "Please enter your password to make changes in system packages: "); diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 76bdcdd468fb..1b569176e27e 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -17,6 +17,7 @@ package com.jetbrains.python.psi.types; import com.intellij.openapi.extensions.Extensions; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyNames; @@ -25,6 +26,7 @@ import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.impl.PyTypeProvider; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; +import com.jetbrains.python.pyi.PyiFile; import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -609,6 +611,7 @@ public class PyTypeChecker { subClass.isSubclass(superClass, context) || PyABCUtil.isSubclass(subClass, superClass, context) || isStrUnicodeMatch(subClass, superClass) || + isBytearrayBytesStringMatch(subClass, superClass) || PyUtil.hasUnresolvedAncestors(subClass, context)) { return true; } @@ -623,6 +626,19 @@ public class PyTypeChecker { return PyNames.TYPE_STR.equals(subClass.getName()) && PyNames.TYPE_UNICODE.equals(superClass.getName()); } + private static boolean isBytearrayBytesStringMatch(@NotNull PyClass subClass, @NotNull PyClass superClass) { + if (!PyNames.TYPE_BYTEARRAY.equals(subClass.getName())) return false; + + final PsiFile subClassFile = subClass.getContainingFile(); + + final boolean isPy2 = subClassFile instanceof PyiFile + ? PyBuiltinCache.getInstance(subClass).getObjectType(PyNames.TYPE_UNICODE) != null + : LanguageLevel.forElement(subClass).isOlderThan(LanguageLevel.PYTHON30); + + final String superClassName = superClass.getName(); + return isPy2 && PyNames.TYPE_STR.equals(superClassName) || !isPy2 && PyNames.TYPE_BYTES.equals(superClassName); + } + @Nullable public static Boolean isCallable(@Nullable PyType type) { if (type == null) { diff --git a/python/src/com/jetbrains/python/testing/PyTestsShared.kt b/python/src/com/jetbrains/python/testing/PyTestsShared.kt index 8f6e33a4fbc9..b1ee4474ec2e 100644 --- a/python/src/com/jetbrains/python/testing/PyTestsShared.kt +++ b/python/src/com/jetbrains/python/testing/PyTestsShared.kt @@ -700,7 +700,7 @@ object PyTestsConfigurationProducer : com.jetbrains.python.testing.AbstractPytho } } } - element = element.parent + element = element.parent ?: break } while (element !is com.intellij.psi.PsiDirectory) // if parent is folder, then we are at file level return null diff --git a/python/testData/inspections/PyPackageRequirementsInspection/ImportsNotInRequirementsTxt/test1.py b/python/testData/inspections/PyPackageRequirementsInspection/ImportsNotInRequirementsTxt/test1.py index 24b98b4a04ec..fe9a411a2ea4 100644 --- a/python/testData/inspections/PyPackageRequirementsInspection/ImportsNotInRequirementsTxt/test1.py +++ b/python/testData/inspections/PyPackageRequirementsInspection/ImportsNotInRequirementsTxt/test1.py @@ -1,9 +1,9 @@ import pip -import opster -from clevercss import convert -import django.conf +import opster +from clevercss import convert +import django.conf import httplib -import test3 +import test3 print('Hello, World!') diff --git a/python/testData/inspections/PyRedeclarationInspection/singleUnderscore.py b/python/testData/inspections/PyRedeclarationInspection/singleUnderscore.py new file mode 100644 index 000000000000..3441f1f9341e --- /dev/null +++ b/python/testData/inspections/PyRedeclarationInspection/singleUnderscore.py @@ -0,0 +1,5 @@ +f2e = [(f, e) for _, e, f in [(1, 2, 3)]] +e2f = [(e, f) for _, e, f in [(1, 2, 3)]] + +array = [1, 2, 3] +_, mid, _ = array \ No newline at end of file diff --git a/python/testData/inspections/PyRedeclarationInspection/underscorePrefixed.py b/python/testData/inspections/PyRedeclarationInspection/underscorePrefixed.py new file mode 100644 index 000000000000..1aeb1f4b6319 --- /dev/null +++ b/python/testData/inspections/PyRedeclarationInspection/underscorePrefixed.py @@ -0,0 +1,12 @@ +def foo(_a): + _a = 10 + + +l = lambda _a: [_a for _a in []] + + +f2e = [(f, e) for _a, e, f in [(1, 2, 3)]] +e2f = [(e, f) for _a, e, f in [(1, 2, 3)]] + +array = [1, 2, 3] +_a, mid, _a = array \ No newline at end of file diff --git a/python/testData/inspections/PyShadowingNamesInspection/test.py b/python/testData/inspections/PyShadowingNamesInspection/test.py index b87b8b27bae3..883734bcc642 100644 --- a/python/testData/inspections/PyShadowingNamesInspection/test.py +++ b/python/testData/inspections/PyShadowingNamesInspection/test.py @@ -44,3 +44,24 @@ def test_outer_comprehensions(): print([y for y in range(10)]) def f(x, y): pass + + +def test_outer_single_underscore(): + _ = "abc" + def foo(): + _ = "def" + + +# PY-3996 +def test_outer_underscore_prefixed(): + _a = "abc" + def foo(): + _a = "def" + + +# PY-3996 +def test_outer_underscore_prefixed_parameter(): + def foo(_a): + def bar(_a): + print(_a) + print(_a) diff --git a/python/testData/inspections/PyTypeCheckerInspection/PromotingBytearrayToBytes.py b/python/testData/inspections/PyTypeCheckerInspection/PromotingBytearrayToBytes.py new file mode 100644 index 000000000000..e39544bf88a8 --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/PromotingBytearrayToBytes.py @@ -0,0 +1,5 @@ +def f(bar: bytes): + return bar + + +f(bytearray()) \ No newline at end of file diff --git a/python/testData/inspections/PyTypeCheckerInspection/PromotingBytearrayToStrAndUnicode.py b/python/testData/inspections/PyTypeCheckerInspection/PromotingBytearrayToStrAndUnicode.py new file mode 100644 index 000000000000..7af7520ce639 --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/PromotingBytearrayToStrAndUnicode.py @@ -0,0 +1,6 @@ +def f(bar): + # type: (str) -> str + return bar + + +f(bytearray()) \ No newline at end of file diff --git a/python/testData/inspections/PyUnusedLocalInspection/singleUnderscore.py b/python/testData/inspections/PyUnusedLocalInspection/singleUnderscore.py new file mode 100644 index 000000000000..18fb14498629 --- /dev/null +++ b/python/testData/inspections/PyUnusedLocalInspection/singleUnderscore.py @@ -0,0 +1,3 @@ +def foo(): + l = [42 for _ in xrange(100)] + print(l) \ No newline at end of file diff --git a/python/testData/inspections/PyUnusedLocalInspection/underscorePrefixed.py b/python/testData/inspections/PyUnusedLocalInspection/underscorePrefixed.py new file mode 100644 index 000000000000..d48832ae25cc --- /dev/null +++ b/python/testData/inspections/PyUnusedLocalInspection/underscorePrefixed.py @@ -0,0 +1,7 @@ +def foo(): + l = [42 for _a in xrange(100)] + print(l) + + +def bar(_a): + print(10) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java index b2802b975dd2..8dfe81e8f7bb 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java @@ -250,4 +250,9 @@ public class Py3TypeCheckerInspectionTest extends PyTestCase { public void testInitializingTypingNamedTuple() { doTest(); } + + // PY-24287 + public void testPromotingBytearrayToBytes() { + doTest(); + } } diff --git a/python/testSrc/com/jetbrains/python/inspections/PyRedeclarationInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyRedeclarationInspectionTest.java index 918151e9e6f4..259c27d8b845 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyRedeclarationInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyRedeclarationInspectionTest.java @@ -94,6 +94,16 @@ public class PyRedeclarationInspectionTest extends PyTestCase { runWithLanguageLevel(LanguageLevel.PYTHON36, this::doTest); } + // PY-18375, PY-24408 + public void testSingleUnderscore() { + doTest(); + } + + // PY-3996 + public void testUnderscorePrefixed() { + doTest(); + } + private void doTest() { final String path = "inspections/PyRedeclarationInspection/" + getTestName(true) + ".py"; diff --git a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java index 9104fa360eb9..3ba98ae8c05f 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java @@ -412,4 +412,9 @@ public class PyTypeCheckerInspectionTest extends PyTestCase { public void testMatchingModuleAgainstStructuralType() { doMultiFileTest(); } + + // PY-24287 + public void testPromotingBytearrayToStrAndUnicode() { + doTest(); + } } diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnusedLocalInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnusedLocalInspectionTest.java index ed3ec5fdf8e2..030625d5060e 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnusedLocalInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnusedLocalInspectionTest.java @@ -82,6 +82,15 @@ public class PyUnusedLocalInspectionTest extends PyTestCase { runWithLanguageLevel(LanguageLevel.PYTHON35, this::doTest); } + public void testSingleUnderscore() { + doTest(); + } + + // PY-3996 + public void testUnderscorePrefixed() { + doTest(); + } + private void doTest() { final String path = "inspections/PyUnusedLocalInspection/" + getTestName(true) + ".py"; diff --git a/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java b/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java index d4b2f801df35..26230463d676 100644 --- a/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java +++ b/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java @@ -109,7 +109,6 @@ public final class PyTestSdkTools { final SdkModificator modificator = sdk.getSdkModificator(); - modificator.removeRoots(OrderRootType.CLASSES); modificator.setSdkAdditionalData(new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(sdk))); diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index 634c20b0bc64..a7dcafea0328 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -208,6 +208,7 @@ label.base.renderer.configurable.enable.toString=Enable 't&oString()' object vie label.base.renderer.configurable.all.overriding=For all classes that override 'toString()' method label.base.renderer.configurable.classes.from.list=For classes from the list: label.compound.renderer.configurable.show.type=Show type and object id +label.compound.renderer.configurable.ondemand=On-demand label.compound.renderer.configurable.use.default.renderer=Use default renderer label.compound.renderer.configurable.use.expression=Use following expression: label.compound.renderer.configurable.use.expression.list=Use list of expressions: diff --git a/resources/src/idea/JavaActions.xml b/resources/src/idea/JavaActions.xml index 676ef3dbc23f..d212692e1d9e 100644 --- a/resources/src/idea/JavaActions.xml +++ b/resources/src/idea/JavaActions.xml @@ -83,7 +83,7 @@ - + diff --git a/slowCheck/src/slowCheck/Generator.java b/slowCheck/src/slowCheck/Generator.java index d11922d9d021..492c7dc03d40 100644 --- a/slowCheck/src/slowCheck/Generator.java +++ b/slowCheck/src/slowCheck/Generator.java @@ -34,7 +34,11 @@ public final class Generator { } public Generator map(@NotNull Function fun) { - return from(data -> fun.apply(generateUnstructured(data))); + return from(data -> fun.apply(myFunction.apply(data))); + } + + public Generator flatMap(@NotNull Function> fun) { + return from(data -> fun.apply(generateValue(data)).generateValue(data)); } public Generator noShrink() { diff --git a/slowCheck/src/slowCheck/GeneratorException.java b/slowCheck/src/slowCheck/GeneratorException.java new file mode 100644 index 000000000000..6cc9ea143a50 --- /dev/null +++ b/slowCheck/src/slowCheck/GeneratorException.java @@ -0,0 +1,11 @@ +package slowCheck; + +/** + * @author peter + */ +public class GeneratorException extends RuntimeException { + + GeneratorException(long seed, Throwable cause) { + super("Exception while generating data, seed=" + seed, cause); + } +} diff --git a/slowCheck/src/slowCheck/PropertyChecker.java b/slowCheck/src/slowCheck/PropertyChecker.java index 6859c043ec8e..d6ec3b6e7cc3 100644 --- a/slowCheck/src/slowCheck/PropertyChecker.java +++ b/slowCheck/src/slowCheck/PropertyChecker.java @@ -79,7 +79,13 @@ public class PropertyChecker { private CounterExampleImpl findCounterExample(int sizeHint) { for (int i = 0; i < 100; i++) { StructureNode node = new StructureNode(); - T value = generator.generateUnstructured(new GenerativeDataStructure(random, node, sizeHint)); + T value; + try { + value = generator.generateUnstructured(new GenerativeDataStructure(random, node, sizeHint)); + } + catch (Throwable e) { + throw new GeneratorException(seed, e); + } if (!generatedHashes.add(node.hashCode())) continue; return CounterExampleImpl.checkProperty(property, value, node); @@ -92,12 +98,18 @@ public class PropertyChecker { private CounterExampleImpl minimized; private int totalSteps; private int sizeHint; + private Throwable stoppingReason; PropertyFailureImpl(@NotNull CounterExampleImpl initial, int sizeHint) { this.initial = initial; this.minimized = initial; this.sizeHint = sizeHint; - shrink(); + try { + shrink(); + } + catch (Throwable e) { + stoppingReason = e; + } } @NotNull @@ -112,6 +124,12 @@ public class PropertyChecker { return minimized; } + @Nullable + @Override + public Throwable getStoppingReason() { + return stoppingReason; + } + @Override public int getTotalMinimizationStepCount() { return totalSteps; diff --git a/slowCheck/src/slowCheck/PropertyFailure.java b/slowCheck/src/slowCheck/PropertyFailure.java index 3c2fbb7b5888..5999ebc19c37 100644 --- a/slowCheck/src/slowCheck/PropertyFailure.java +++ b/slowCheck/src/slowCheck/PropertyFailure.java @@ -12,6 +12,9 @@ public interface PropertyFailure { @NotNull CounterExample getMinimalCounterexample(); + + @Nullable + Throwable getStoppingReason(); int getTotalMinimizationStepCount(); diff --git a/slowCheck/src/slowCheck/PropertyFalsified.java b/slowCheck/src/slowCheck/PropertyFalsified.java index b2298def84c7..75334dfcb8a7 100644 --- a/slowCheck/src/slowCheck/PropertyFalsified.java +++ b/slowCheck/src/slowCheck/PropertyFalsified.java @@ -1,5 +1,9 @@ package slowCheck; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; import java.util.function.Supplier; /** @@ -7,19 +11,63 @@ import java.util.function.Supplier; */ @SuppressWarnings("ExceptionClassNameDoesntEndWithException") public class PropertyFalsified extends RuntimeException { + static final String FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION = "!!! FAILURE REASON HAS CHANGED DURING MINIMIZATION !!!"; + private final long seed; private final PropertyFailure failure; private final Supplier data; - public PropertyFalsified(int seed, PropertyFailure failure, Supplier data) { - super("Falsified on " + failure.getMinimalCounterexample().getExampleValue() + "\n" + - (failure.getTotalMinimizationStepCount() > 0 - ? "Minimized in " + failure.getTotalMinimizationStepCount() + " steps\n" - : "") + - "Seed=" + seed, failure.getMinimalCounterexample().getExceptionCause()); + PropertyFalsified(long seed, PropertyFailure failure, Supplier data) { + super(failure.getMinimalCounterexample().getExceptionCause()); + this.seed = seed; this.failure = failure; this.data = data; } + @Override + public String getMessage() { + int minimizationStepCount = failure.getTotalMinimizationStepCount(); + String msg = "Falsified on " + failure.getMinimalCounterexample().getExampleValue() + "\n" + + (minimizationStepCount > 0 ? "Minimized in " + minimizationStepCount + " steps\n" : "") + + "Seed=" + seed; + Throwable first = failure.getFirstCounterExample().getExceptionCause(); + if (exceptionsDiffer(first, failure.getMinimalCounterexample().getExceptionCause())) { + msg += "\n " + FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION; + if (first != null) { + msg += "\n Initial exception: " + printStackTrace(first) + "\n==========================\n"; + } else { + msg += "\n Initially property was falsified without exceptions\n"; + } + } + return msg; + } + + private static boolean exceptionsDiffer(Throwable e1, Throwable e2) { + if (e1 == null && e2 == null) return false; + if ((e1 == null) != (e2 == null)) return true; + if (!e1.getClass().equals(e2.getClass())) return true; + + return !getUserTrace(e1).equals(getUserTrace(e2)); + } + + private static List getUserTrace(Throwable e) { + List result = new ArrayList<>(); + for (StackTraceElement element : e.getStackTrace()) { + String s = element.toString(); + if (s.startsWith("slowCheck.CounterExampleImpl.checkProperty")) { + break; + } + result.add(s); + } + return result; + } + + private static String printStackTrace(Throwable e) { + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + e.printStackTrace(writer); + return stringWriter.getBuffer().toString(); + } + public PropertyFailure getFailure() { return failure; } diff --git a/slowCheck/test/slowCheck/ExceptionTest.java b/slowCheck/test/slowCheck/ExceptionTest.java new file mode 100644 index 000000000000..3494cc88106d --- /dev/null +++ b/slowCheck/test/slowCheck/ExceptionTest.java @@ -0,0 +1,87 @@ +package slowCheck; + +import static slowCheck.Generator.from; +import static slowCheck.Generator.integers; +import static slowCheck.Generator.listsOf; + +/** + * @author peter + */ +public class ExceptionTest extends PropertyCheckerTestCase { + + public void testFailureReasonUnchanged() { + try { + PropertyChecker.forAll(ourTestSettings, integers(), i -> { + throw new AssertionError("fail"); + }); + fail(); + } + catch (PropertyFalsified e) { + assertFalse(e.getMessage().contains(PropertyFalsified.FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION)); + } + } + + public void testFailureReasonChangedExceptionClass() { + try { + PropertyChecker.forAll(ourTestSettings, integers(), i -> { + throw (i == 0 ? new RuntimeException("fail") : new IllegalArgumentException("fail")); + }); + fail(); + } + catch (PropertyFalsified e) { + assertTrue(e.getMessage().contains(PropertyFalsified.FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION)); + } + } + + public void testFailureReasonChangedExceptionTrace() { + try { + PropertyChecker.forAll(ourTestSettings, integers(), i -> { + if (i == 0) { + throw new AssertionError("fail"); + } + else { + throw new AssertionError("fail2"); + } + }); + fail(); + } + catch (PropertyFalsified e) { + assertTrue(e.getMessage().contains(PropertyFalsified.FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION)); + } + } + + public void testExceptionWhileGeneratingValue() { + try { + PropertyChecker.forAll(ourTestSettings, from(data -> { + throw new AssertionError("fail"); + }), i -> true); + fail(); + } + catch (GeneratorException ignore) { + } + } + + public void testExceptionWhileShrinkingValue() { + try { + PropertyChecker.forAll(ourTestSettings, listsOf(integers()).suchThat(l -> { + if (l.size() == 1 && l.get(0) == 0) throw new RuntimeException("my exception"); + return true; + }), l -> l.stream().allMatch(i -> i > 0)); + fail(); + } + catch (PropertyFalsified e) { + assertEquals("my exception", e.getFailure().getStoppingReason().getMessage()); + } + } + + public void testUnsatisfiableSuchThat() { + try { + PropertyChecker.forAll(integers(-1, 1).suchThat(i -> i > 2), i -> i == 0); + fail(); + } + catch (GeneratorException e) { + assertTrue(e.getCause() instanceof CannotSatisfyCondition); + } + } + +} diff --git a/slowCheck/test/slowCheck/GeneratorTest.java b/slowCheck/test/slowCheck/GeneratorTest.java index beca7deede24..ad83d8c2a6a3 100644 --- a/slowCheck/test/slowCheck/GeneratorTest.java +++ b/slowCheck/test/slowCheck/GeneratorTest.java @@ -1,12 +1,9 @@ package slowCheck; -import junit.framework.TestCase; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.function.Predicate; import java.util.stream.Collectors; import static slowCheck.Generator.*; @@ -14,8 +11,7 @@ import static slowCheck.Generator.*; /** * @author peter */ -public class GeneratorTest extends TestCase { - private static final CheckerSettings ourTestSettings = CheckerSettings.DEFAULT_SETTINGS.withSeed(0); +public class GeneratorTest extends PropertyCheckerTestCase { public void testMod() { checkFalsified(integers(), @@ -75,25 +71,10 @@ public class GeneratorTest extends TestCase { return true; } - public void testPropertyThrowsException() { - checkFalsified(integers(), p -> { - throw new AssertionError(p); - }, 1); - } - public void testSuchThat() { PropertyChecker.forAll(integers().suchThat(i -> i < 0), i -> i < 0); } - public void testUnsatisfiableSuchThat() { - try { - PropertyChecker.forAll(integers(-1, 1).suchThat(i -> i > 2), i -> i == 0); - fail(); - } - catch (CannotSatisfyCondition ignored) { - } - } - public void testStringOfStringChecksAllChars() { checkFalsified(stringsOf("abc "), s -> !s.contains(" "), @@ -145,22 +126,4 @@ public class GeneratorTest extends TestCase { assertEquals(1, failure.getMinimalCounterexample().getExampleValue().size()); } - private PropertyFailure checkFalsified(Generator generator, Predicate predicate, int minimizationSteps) { - try { - PropertyChecker.forAll(ourTestSettings, generator, predicate); - throw new AssertionError("Can't falsify " + getName()); - } - catch (PropertyFalsified e) { - //noinspection unchecked - PropertyFailure failure = (PropertyFailure)e.getFailure(); - - System.out.println(" " + getName()); - System.out.println("Value: " + e.getBreakingValue()); - System.out.println("Data: " + e.getData()); - assertEquals(minimizationSteps, failure.getTotalMinimizationStepCount()); - assertEquals(e.getBreakingValue(), generator.generateUnstructured(e.getData())); - - return failure; - } - } } diff --git a/slowCheck/test/slowCheck/PropertyCheckerTestCase.java b/slowCheck/test/slowCheck/PropertyCheckerTestCase.java new file mode 100644 index 000000000000..7f1dc2d5b70f --- /dev/null +++ b/slowCheck/test/slowCheck/PropertyCheckerTestCase.java @@ -0,0 +1,32 @@ +package slowCheck; + +import junit.framework.TestCase; + +import java.util.function.Predicate; + +/** + * @author peter + */ +abstract class PropertyCheckerTestCase extends TestCase { + protected static final CheckerSettings ourTestSettings = CheckerSettings.DEFAULT_SETTINGS.withSeed(0); + + protected PropertyFailure checkFalsified(Generator generator, Predicate predicate, int minimizationSteps) { + try { + PropertyChecker.forAll(ourTestSettings, generator, predicate); + throw new AssertionError("Can't falsify " + getName()); + } + catch (PropertyFalsified e) { + //noinspection unchecked + PropertyFailure failure = (PropertyFailure)e.getFailure(); + + System.out.println(" " + getName()); + System.out.println("Value: " + e.getBreakingValue()); + System.out.println("Data: " + e.getData()); + assertEquals(minimizationSteps, failure.getTotalMinimizationStepCount()); + assertEquals(e.getBreakingValue(), generator.generateUnstructured(e.getData())); + + return failure; + } + } + +} diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetPreviewHint.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetPreviewHint.java index 4b7bfa76125f..b4eaf719685d 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetPreviewHint.java +++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetPreviewHint.java @@ -105,15 +105,17 @@ public class EmmetPreviewHint extends LightweightHint implements Disposable { public void updateText(@NotNull final Producer contentProducer) { myAlarm.cancelAllRequests(); myAlarm.addRequest(() -> { - if (!isDisposed) { - final String newText = contentProducer.produce(); - if (StringUtil.isEmpty(newText)) { - hide(); + DocumentUtil.writeInRunUndoTransparentAction(() -> { + if (!isDisposed) { + final String newText = contentProducer.produce(); + if (StringUtil.isEmpty(newText)) { + hide(); + } + else if (!myEditor.getDocument().getText().equals(newText)) { + myEditor.getDocument().setText(newText); + } } - else if (!myEditor.getDocument().getText().equals(newText)) { - DocumentUtil.writeInRunUndoTransparentAction(() -> myEditor.getDocument().setText(newText)); - } - } + }); }, 100); }