mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
Generated
-1
@@ -26,7 +26,6 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/android/rt/android-rt.iml" filepath="$PROJECT_DIR$/android/rt/android-rt.iml" group="android" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/annotations/annotations.iml" filepath="$PROJECT_DIR$/platform/annotations/annotations.iml" group="platform" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/annotations/common/annotations-common.iml" filepath="$PROJECT_DIR$/platform/annotations/common/annotations-common.iml" group="platform" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/annotations/internal/annotations-internal.iml" filepath="$PROJECT_DIR$/platform/annotations/internal/annotations-internal.iml" group="platform" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/annotations/java8/annotations-java8.iml" filepath="$PROJECT_DIR$/platform/annotations/java8/annotations-java8.iml" group="platform" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/ant/ant.iml" filepath="$PROJECT_DIR$/plugins/ant/ant.iml" group="plugins" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/ant/jps-plugin/ant-jps-plugin.iml" filepath="$PROJECT_DIR$/plugins/ant/jps-plugin/ant-jps-plugin.iml" group="plugins" />
|
||||
|
||||
@@ -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 ");
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
-->
|
||||
<project name="Patches and repackages ASM library" default="package">
|
||||
<!-- set this property to the path to a downloaded ASM source .jar file -->
|
||||
<property name="asm.src" value=""/>
|
||||
<property name="asm.src" value="/home/sher/asm-src.zip"/>
|
||||
|
||||
<property name="src.dir" value="${basedir}/src"/>
|
||||
<property name="out.dir" value="${basedir}/out"/>
|
||||
@@ -42,7 +42,6 @@
|
||||
<patch dir="${src.dir}" strip="0" patchfile="1_version_check.patch" failonerror="true"/>
|
||||
<patch dir="${src.dir}" strip="0" patchfile="2_coverage_fix.patch" failonerror="true"/>
|
||||
<patch dir="${src.dir}" strip="0" patchfile="3_api_version.patch" failonerror="true"/>
|
||||
<patch dir="${src.dir}" strip="0" patchfile="4_textifier_transient_method.patch" failonerror="true"/>
|
||||
<delete file="${src.dir}/org/objectweb/asm/optimizer/ModuleInfoBndPlugin.java" quiet="true"/>
|
||||
</target>
|
||||
|
||||
|
||||
+3
-2
@@ -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<CompositePackagingElement<?>> 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<CompositePackagingElement<?>> getParents() {
|
||||
|
||||
@@ -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);
|
||||
|
||||
+12
-3
@@ -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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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> T getUserData(Key<T> key) {
|
||||
return ValueDescriptorImpl.this.getUserData(key);
|
||||
}
|
||||
};
|
||||
descriptor.myFullValue = true;
|
||||
return descriptor;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+67
-25
@@ -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<Boolean>("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<Boolean>("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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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> T getUserData(Key<T> key);
|
||||
<T> void putUserData(Key<T> key, T value);
|
||||
|
||||
void displayAs(NodeDescriptor descriptor);
|
||||
|
||||
void setAncestor(NodeDescriptor oldDescriptor);
|
||||
|
||||
@@ -35,9 +35,15 @@ public interface RefJavaModule extends RefElement {
|
||||
@NotNull
|
||||
Map<String, List<String>> getExportedPackageNames();
|
||||
|
||||
@NotNull
|
||||
Set<RefClass> getServiceInterfaces();
|
||||
|
||||
@NotNull
|
||||
Set<RefClass> getServiceImplementations();
|
||||
|
||||
@NotNull
|
||||
Set<RefClass> getUsedServices();
|
||||
|
||||
@NotNull
|
||||
List<RequiredModule> getRequiredModules();
|
||||
|
||||
|
||||
@@ -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<MethodSignatureBackedByPsiMethod> 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);
|
||||
}
|
||||
}
|
||||
|
||||
+121
-38
@@ -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<String, List<String>> 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<String> exportedPackageNames = getExportedPackageNames(javaModule);
|
||||
if (exportedPackageNames.contains(packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Set<String> 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<String> exportedPackageNames = getExportedPackageNames(javaModule);
|
||||
if (exportedPackageNames.contains(packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isServiceClass(@NotNull PsiClass psiClass, @NotNull PsiJavaModule javaModule) {
|
||||
Set<String> 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<String> getServiceImplementationNames(@NotNull PsiJavaModule javaModule) {
|
||||
return CachedValuesManager.getCachedValue(javaModule, () -> {
|
||||
Set<String> 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<String> collectServiceClassNames(@NotNull PsiJavaModule javaModule) {
|
||||
Set<String> classes = StreamEx.of(javaModule.getProvides().spliterator())
|
||||
.map(PsiProvidesStatement::getImplementationList)
|
||||
.nonNull()
|
||||
.map(PsiReferenceList::getReferenceElements)
|
||||
.flatMap(Arrays::stream)
|
||||
.map(PsiJavaCodeReferenceElement::getQualifiedName)
|
||||
.nonNull()
|
||||
.toCollection(THashSet::new);
|
||||
|
||||
Set<String> usages = StreamEx.of(javaModule.getUses().iterator())
|
||||
.map(PsiUsesStatement::getClassReference)
|
||||
.nonNull()
|
||||
.map(PsiJavaCodeReferenceElement::getQualifiedName)
|
||||
.nonNull()
|
||||
.toCollection(THashSet::new);
|
||||
|
||||
classes.addAll(usages);
|
||||
return classes;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+117
-67
@@ -33,7 +33,9 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule {
|
||||
private final RefModule myRefModule;
|
||||
|
||||
private Map<String, List<String>> myExportedPackageNames;
|
||||
private Set<RefClass> myServiceInterfaces;
|
||||
private Set<RefClass> myServiceImplementations;
|
||||
private Set<RefClass> myUsedServices;
|
||||
private List<RequiredModule> 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<RefClass> getServiceInterfaces() {
|
||||
return myServiceInterfaces != null ? myServiceInterfaces : Collections.emptySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<RefClass> getServiceImplementations() {
|
||||
return myServiceImplementations != null ? myServiceImplementations : Collections.emptySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<RefClass> getUsedServices() {
|
||||
return myUsedServices != null ? myUsedServices : Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<RequiredModule> 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<String, List<String>> 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<String> 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<String, List<String>> 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<String> toModuleNames = myExportedPackageNames.get(packageName);
|
||||
if (toModuleNames == emptyList) myExportedPackageNames.put(packageName, toModuleNames = new ArrayList<>(1));
|
||||
toModuleNames.add(((PsiJavaModule)moduleElement).getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
List<String> 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<String> 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<PsiElement> resolvedElements = new ArrayList<>();
|
||||
if (reference != null) {
|
||||
|
||||
+8
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+26
-30
@@ -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<RefClass> 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<String, List<String>> exportedPackageNames = refJavaModule.getExportedPackageNames();
|
||||
if (exportedPackageNames.containsKey(refOwner.getQualifiedName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
private boolean keepVisibilityLevel(RefJavaElement refElement) {
|
||||
return StreamEx.of(ExtensionPointName.<EntryPoint>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.<EntryPoint>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.<EntryPoint>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;
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -172,6 +172,7 @@ public class SliceLeafAnalyzer {
|
||||
|
||||
public static Map<SliceNode, Collection<PsiElement>> createMap() {
|
||||
return new FactoryMap<SliceNode, Collection<PsiElement>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<SliceNode, Collection<PsiElement>> createMap() {
|
||||
return ContainerUtil.newConcurrentMap(ContainerUtil.<SliceNode>identityStrategy());
|
||||
|
||||
@@ -137,6 +137,7 @@ public class SliceNullnessAnalyzer {
|
||||
return new NullAnalysisResult();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<SliceNode, NullAnalysisResult> createMap() {
|
||||
return ContainerUtil.newIdentityTroveMap();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -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();
|
||||
|
||||
+9
-3
@@ -53,9 +53,11 @@ public class JavaOverridingMethodsSearcher implements QueryExecutor<PsiMethod, O
|
||||
Project project = ReadAction.compute(method::getProject);
|
||||
final SearchScope searchScope = parameters.getScope();
|
||||
|
||||
if (searchScope instanceof LocalSearchScope &&
|
||||
Arrays.stream(((LocalSearchScope)searchScope).getVirtualFiles()).allMatch(file -> 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<PsiMethod> cached = HighlightingCaches.getInstance(project).OVERRIDING_METHODS.get(method);
|
||||
@@ -79,6 +81,10 @@ public class JavaOverridingMethodsSearcher implements QueryExecutor<PsiMethod, O
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isJavaOnlyScope(@NotNull VirtualFile[] files) {
|
||||
return Arrays.stream(files).allMatch(file -> file.getFileType() == JavaFileType.INSTANCE);
|
||||
}
|
||||
|
||||
private static boolean processLocalScope(@NotNull LocalSearchScope searchScope,
|
||||
@NotNull PsiMethod method,
|
||||
@NotNull Project project,
|
||||
|
||||
@@ -86,13 +86,10 @@ public class AnnotationUtil {
|
||||
}
|
||||
|
||||
private static PsiAnnotation findOwnAnnotation(final PsiModifierListOwner listOwner, Collection<String> annotationNames) {
|
||||
ConcurrentFactoryMap<Collection<String>, PsiAnnotation> map = CachedValuesManager.getCachedValue(
|
||||
Map<Collection<String>, PsiAnnotation> map = CachedValuesManager.getCachedValue(
|
||||
listOwner,
|
||||
() -> {
|
||||
ConcurrentFactoryMap<Collection<String>, PsiAnnotation> value = new ConcurrentFactoryMap<Collection<String>, PsiAnnotation>() {
|
||||
@Nullable
|
||||
@Override
|
||||
protected PsiAnnotation create(Collection<String> annotationNames1) {
|
||||
Map<Collection<String>, 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<String> annotationNames) {
|
||||
ConcurrentFactoryMap<Collection<String>, PsiAnnotation> map = CachedValuesManager.getCachedValue(
|
||||
Map<Collection<String>, PsiAnnotation> map = CachedValuesManager.getCachedValue(
|
||||
listOwner,
|
||||
() -> {
|
||||
ConcurrentFactoryMap<Collection<String>, PsiAnnotation> value = new ConcurrentFactoryMap<Collection<String>, PsiAnnotation>() {
|
||||
@Nullable
|
||||
@Override
|
||||
protected PsiAnnotation create(Collection<String> annotationNames1) {
|
||||
Map<Collection<String>, 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<Set<String>, PsiAnnotation> map = CachedValuesManager.getCachedValue(
|
||||
Map<Set<String>, PsiAnnotation> map = CachedValuesManager.getCachedValue(
|
||||
listOwner,
|
||||
() -> {
|
||||
ConcurrentFactoryMap<Set<String>, PsiAnnotation> value = new ConcurrentFactoryMap<Set<String>, PsiAnnotation>() {
|
||||
@Nullable
|
||||
@Override
|
||||
protected PsiAnnotation create(Set<String> annotationNames1) {
|
||||
Map<Set<String>, 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<PsiMember> processed) {
|
||||
@NotNull String annotationFQN,
|
||||
boolean checkHierarchy,
|
||||
boolean skipExternal,
|
||||
boolean skipInferred,
|
||||
@Nullable Set<PsiMember> 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();
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// "Annotate overridden methods as '@NotNull'" "true"
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
abstract class P2 {
|
||||
@NotNull<caret>
|
||||
String foo(@NotNull String p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
Object o = new P2() {
|
||||
@NotNull
|
||||
@Override
|
||||
String foo(String p) {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// "Annotate overridden methods as '@NotNull'" "true"
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
abstract class P2 {
|
||||
@NotNull<caret>
|
||||
String foo(@NotNull String p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
Object o = new P2() {
|
||||
@Override
|
||||
String foo(String p) {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package foo.bar;
|
||||
|
||||
public class Public {}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package foo.bar;
|
||||
|
||||
public class ServiceApi {}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package foo.bar;
|
||||
|
||||
public class ServiceImpl extends ServiceApi {}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package foo.bar;
|
||||
|
||||
public class UsedService {}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
<problem>
|
||||
<file>Public.java</file>
|
||||
<line>3</line>
|
||||
<entry_point TYPE="class" FQNAME="foo.bar.Public" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Declaration access can be weaker</problem_class>
|
||||
<description>Can be package-private</description>
|
||||
</problem>
|
||||
</problems>
|
||||
@@ -0,0 +1,3 @@
|
||||
package foo.bar;
|
||||
|
||||
public class Api {}
|
||||
@@ -0,0 +1,4 @@
|
||||
package foo.bar.impl;
|
||||
import foo.bar Api;
|
||||
|
||||
public class Impl extends Api {}
|
||||
@@ -0,0 +1,4 @@
|
||||
package foo.bar.impl;
|
||||
import foo.bar Api;
|
||||
|
||||
public class Other extends Api {}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
<problem>
|
||||
<file>Other.java</file>
|
||||
<line>4</line>
|
||||
<entry_point TYPE="class" FQNAME="foo.bar.impl.Other" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Declaration access can be weaker</problem_class>
|
||||
<description>Can be package-private</description>
|
||||
</problem>
|
||||
</problems>
|
||||
+13
@@ -67,3 +67,16 @@ public class AnnotateMethodTest extends LightQuickFixTestCase {
|
||||
return LanguageLevel.JDK_1_5;
|
||||
}
|
||||
}
|
||||
abstract class P2 {
|
||||
@NotNull<caret>
|
||||
String foo(@NotNull String p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
Object o = new P2() {
|
||||
@Override
|
||||
String foo(String p) {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
}
|
||||
+32
-31
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)) }
|
||||
))
|
||||
|
||||
+2
-1
@@ -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());
|
||||
|
||||
|
||||
+1
-2
@@ -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);
|
||||
|
||||
|
||||
@@ -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<JsonSchemaType> PRIMITIVE_TYPES =
|
||||
ContainerUtil.set(JsonSchemaType._integer, JsonSchemaType._number, JsonSchemaType._boolean, JsonSchemaType._string, JsonSchemaType._null);
|
||||
private final Map<PsiElement, String> 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<JsonSchemaObject> oneOf) {
|
||||
final Map<PsiElement, String> errors = new HashMap<>();
|
||||
boolean wasTypeError = false;
|
||||
int cntCorrect = 0;
|
||||
final List<JsonSchemaObject> 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<JsonSchemaObject> list) {
|
||||
return list.stream().anyMatch(s -> !StringUtil.isEmptyOrSpaces(s.getFormat()));
|
||||
}
|
||||
|
||||
// returns the schema, selected for annotation
|
||||
private JsonSchemaObject processAnyOf(@NotNull JsonValueAdapter value, List<JsonSchemaObject> anyOf) {
|
||||
final Map<PsiElement, String> errors = new HashMap<>();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<JsonSchemaObject> 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -54,6 +54,7 @@ public class JsonSchemaResolver {
|
||||
return MatchResult.create(node);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<JsonSchemaObject> resolve() {
|
||||
return resolve(false, false, false);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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\": [{<warning descr=\"Property 'foxtrot' is not allowed\">\"foxtrot\": 15</warning>, \"kilo\": 20}]}");
|
||||
}
|
||||
|
||||
@@ -512,6 +512,45 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
doTest(schema, "{\"not_type\": <warning descr=\"String is violating the pattern: '^[a-z]*[0-5]*$'\">\"4a4\"</warning>}");
|
||||
}
|
||||
|
||||
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" +
|
||||
|
||||
@@ -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\": <caret>}", "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, "{<caret>}", "\"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, "{<caret>}", "\"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" +
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Disallows /// <reference path=> imports (use ES6-style imports instead)
|
||||
@@ -0,0 +1 @@
|
||||
my second level property description 1
|
||||
@@ -0,0 +1 @@
|
||||
my property description 1
|
||||
@@ -0,0 +1 @@
|
||||
Description found through definition
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"<caret>source": {}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"definitions": {
|
||||
"target": {
|
||||
"description": "Description found through definition"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"source": {
|
||||
"$ref": "#/definitions/target"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Description found through definition
|
||||
@@ -0,0 +1 @@
|
||||
Description found through definition
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"<caret>source": {}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"definitions": {
|
||||
"target": {
|
||||
"title": "Title found through definition",
|
||||
"description": "Description found through definition"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"source": {
|
||||
"$ref": "#/definitions/target"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Title found through definition
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -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<String> additionalJvmOptions, String defaultMainModule, String excludedSourceDirectory)
|
||||
abstract void runTests(List<String> additionalJvmOptions, String defaultMainModule, Predicate<File> rootExcludeCondition)
|
||||
|
||||
static TestingTasks create(CompilationContext context, TestingOptions options = new TestingOptions()) {
|
||||
return new TestingTasksImpl(context, options)
|
||||
|
||||
-1
@@ -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")
|
||||
|
||||
+5
-5
@@ -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<String> additionalJvmOptions, String defaultMainModule, String excludedSourceDirectory) {
|
||||
void runTests(List<String> additionalJvmOptions, String defaultMainModule, Predicate<File> 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<JpsModule> excludedModules = context.project.modules.findAll {
|
||||
List<String> 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<String> excludedRoots = excludedModules.collectMany {
|
||||
[context.projectBuilder.moduleOutput(it), context.projectBuilder.moduleTestsOutput(it)]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -82,13 +82,13 @@ public abstract class VirtualFileVisitor<T> {
|
||||
|
||||
|
||||
private boolean myFollowSymLinks = true;
|
||||
private boolean mySkipRoot = false;
|
||||
private boolean mySkipRoot;
|
||||
private int myDepthLimit = -1;
|
||||
|
||||
private Map<VirtualFile, List<VirtualFile>> myVisitedTargets;
|
||||
private int myLevel = 0;
|
||||
private Stack<T> myValueStack = null;
|
||||
private T myValue = null;
|
||||
private int myLevel;
|
||||
private Stack<T> myValueStack;
|
||||
private T myValue;
|
||||
|
||||
protected VirtualFileVisitor(@NotNull Option... options) {
|
||||
for (Option option : options) {
|
||||
|
||||
@@ -42,6 +42,7 @@ public abstract class AbstractQuery<Result> implements Query<Result> {
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<Result> iterator() {
|
||||
assertNotProcessing();
|
||||
|
||||
@@ -46,10 +46,7 @@ public final class ExecutorsQuery<Result, Parameter> extends AbstractQuery<Resul
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (IndexNotReadyException e) {
|
||||
catch (ProcessCanceledException | IndexNotReadyException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.util.Collection;
|
||||
*/
|
||||
public interface Query<Result> extends Iterable<Result> {
|
||||
/**
|
||||
* 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
|
||||
|
||||
+14
-2
@@ -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;
|
||||
|
||||
@@ -85,8 +85,11 @@ public class VirtualFileManagerImpl extends VirtualFileManagerEx {
|
||||
public VirtualFileSystem getFileSystem(@Nullable String protocol) {
|
||||
if (protocol == null) return null;
|
||||
List<VirtualFileSystem> 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);
|
||||
}
|
||||
|
||||
|
||||
+118
-47
@@ -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<ExternalOptionStateComponent>, 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<ExternalOptionStateModule, String?> {
|
||||
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
|
||||
}
|
||||
}
|
||||
+2
-8
@@ -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<ExternalModuleStorage>(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -61,6 +61,11 @@ public class InternalExternalProjectInfo implements ExternalProjectInfo, Seriali
|
||||
return myExternalProjectPath;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getNullSafeExternalProjectPath() {
|
||||
return myExternalProjectPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public DataNode<ProjectData> getExternalProjectStructure() {
|
||||
|
||||
+4
-1
@@ -104,7 +104,10 @@ public class ExternalProjectsDataStorage implements SettingsSavingComponent, Per
|
||||
}
|
||||
}
|
||||
else {
|
||||
markDirty(projectInfo.getExternalProjectPath());
|
||||
String projectPath = projectInfo.getNullSafeExternalProjectPath();
|
||||
if (projectPath != null) {
|
||||
markDirty(projectPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -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<ExternalProjectsState>, 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
|
||||
|
||||
+1
@@ -64,6 +64,7 @@ public class ExternalProjectsState {
|
||||
return new TaskActivationState();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<String, TaskActivationState> createMap() {
|
||||
return new LinkedHashMap<>();
|
||||
|
||||
+4
-1
@@ -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<S extends ExternalP
|
||||
|
||||
protected abstract void fillExtraControls(@NotNull PaintAwarePanel content, int indentLevel);
|
||||
|
||||
@Override
|
||||
public boolean isModified() {
|
||||
boolean result = false;
|
||||
if (!myCustomizer.isUseAutoImportBoxHidden() && myUseAutoImportBox != null) {
|
||||
@@ -93,6 +94,7 @@ public abstract class AbstractExternalProjectSettingsControl<S extends ExternalP
|
||||
|
||||
protected abstract boolean isExtraSettingModified();
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
reset(false);
|
||||
}
|
||||
@@ -133,6 +135,7 @@ public abstract class AbstractExternalProjectSettingsControl<S extends ExternalP
|
||||
|
||||
protected abstract void applyExtraSettings(@NotNull S settings);
|
||||
|
||||
@Override
|
||||
public void disposeUIResources() {
|
||||
ExternalSystemUiUtil.disposeUi(this);
|
||||
}
|
||||
|
||||
+3
-3
@@ -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.
|
||||
@@ -40,6 +40,7 @@ import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -128,8 +129,7 @@ public abstract class AbstractExternalSystemConfigurable<
|
||||
addTitle(ExternalSystemBundle.message("settings.title.project.settings"));
|
||||
List<ProjectSettings> 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) {
|
||||
|
||||
+14
-7
@@ -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 {
|
||||
</module>""")
|
||||
|
||||
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("""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4" />""")
|
||||
<module type="JAVA_MODULE" version="4" />""")
|
||||
|
||||
assertThat(cacheDir.resolve("test@maven.xml")).isEqualTo("""
|
||||
assertThat(cacheDir.resolve("test.xml")).isEqualTo("""
|
||||
<module>
|
||||
<component name="ExternalSystem" externalSystem="Maven" />
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$ESCAPED_MODULE_DIR" />
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -49,6 +49,7 @@ public class ResolveScopeManagerImpl extends ResolveScopeManager {
|
||||
|
||||
private final Map<VirtualFile, GlobalSearchScope> myDefaultResolveScopesCache = new FactoryMap<VirtualFile, GlobalSearchScope>() {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<VirtualFile, GlobalSearchScope> createMap() {
|
||||
return ContainerUtil.createConcurrentWeakKeySoftValueMap();
|
||||
|
||||
@@ -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> LANGUAGE_COMPARATOR = (o1, o2) -> o1.getID().compareTo(o2.getID());
|
||||
public static final Comparator<Language> 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 {
|
||||
* </ul>
|
||||
* <p/>
|
||||
* 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<DataContext> 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<DataContext> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -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<AppEditorFontPanel> myFontPanelInstance = new LazyInstance<AppEditorFontPanel>() {
|
||||
|
||||
+100
-51
@@ -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<FoldingUpdate.RegionInfo> myRegionInfos = new LinkedHashSet<>();
|
||||
private final MultiMap<FoldingGroup, FoldingUpdate.RegionInfo> 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<TextRange, Boolean> rangeToExpandStatusMap) {
|
||||
List<FoldRegion> toRemove = new ArrayList<>();
|
||||
InjectedLanguageManager injectedManager = InjectedLanguageManager.getInstance(myProject);
|
||||
Ref<FoldingUpdate.RegionInfo> infoRef = Ref.create();
|
||||
Set<FoldingGroup> processedGroups = new HashSet<>();
|
||||
List<FoldingUpdate.RegionInfo> 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<FoldRegion> 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<FoldingUpdate.RegionInfo> 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<TextRange, Boolean> rangeToExpandStatusMap, Ref<FoldingUpdate.RegionInfo> 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<FoldingUpdate.RegionInfo> 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<FoldRegion> affectedRegions = group != null && myEditor instanceof EditorEx
|
||||
|
||||
@@ -82,6 +82,7 @@ public class ConsoleHistoryController {
|
||||
|
||||
/** @noinspection MismatchedQueryAndUpdateOfCollection*/
|
||||
private final static FactoryMap<String, ConsoleHistoryModel> ourModels = new FactoryMap<String, ConsoleHistoryModel>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<String, ConsoleHistoryModel> createMap() {
|
||||
return ContainerUtil.createConcurrentWeakValueMap();
|
||||
|
||||
+23
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -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<Usage> usagesSet) {
|
||||
if (usagesSet == null) {
|
||||
private void replaceUsagesUnderCommand(@NotNull final ReplaceContext replaceContext, @NotNull final Set<Usage> usagesSet) {
|
||||
if (usagesSet.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<Element>, 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)) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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<VirtualFile, FileViewProvider> myViewProviders = new ConcurrentWeakFactoryMap<VirtualFile, FileViewProvider>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<VirtualFile, FileViewProvider> createMap() {
|
||||
return ContainerUtil.createConcurrentWeakKeyWeakValueMap();
|
||||
|
||||
+8
-4
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user