Merge remote-tracking branch 'origin/master'

This commit is contained in:
Konstantin Bulenkov
2017-06-30 14:12:38 +03:00
202 changed files with 2319 additions and 1118 deletions
-1
View File
@@ -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 ");
}
+1 -2
View File
@@ -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>
@@ -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);
@@ -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;
}
}
@@ -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);
}
}
@@ -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
@@ -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) {
@@ -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;
}
}
@@ -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;
@@ -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;
}
}
@@ -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();
@@ -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();
@@ -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 "";
}
};
}
@@ -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 "";
}
};
}
@@ -0,0 +1,3 @@
package foo.bar;
public class Public {}
@@ -0,0 +1,3 @@
package foo.bar;
public class ServiceApi {}
@@ -0,0 +1,3 @@
package foo.bar;
public class ServiceImpl extends ServiceApi {}
@@ -0,0 +1,3 @@
package foo.bar;
public class UsedService {}
@@ -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>
@@ -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 "";
}
};
}
@@ -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)) }
))
@@ -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());
@@ -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 /// &lt;reference path=&gt; 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
BIN
View File
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)
@@ -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")
@@ -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
@@ -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);
}
@@ -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
}
}
@@ -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)
}
}
}
@@ -61,6 +61,11 @@ public class InternalExternalProjectInfo implements ExternalProjectInfo, Seriali
return myExternalProjectPath;
}
@Nullable
public String getNullSafeExternalProjectPath() {
return myExternalProjectPath;
}
@Override
@Nullable
public DataNode<ProjectData> getExternalProjectStructure() {
@@ -104,7 +104,10 @@ public class ExternalProjectsDataStorage implements SettingsSavingComponent, Per
}
}
else {
markDirty(projectInfo.getExternalProjectPath());
String projectPath = projectInfo.getNullSafeExternalProjectPath();
if (projectPath != null) {
markDirty(projectPath);
}
}
}
}
@@ -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
@@ -64,6 +64,7 @@ public class ExternalProjectsState {
return new TaskActivationState();
}
@NotNull
@Override
protected Map<String, TaskActivationState> createMap() {
return new LinkedHashMap<>();
@@ -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);
}
@@ -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) {
@@ -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)
}
}
}
@@ -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;
}
}
}
@@ -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>() {
@@ -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();
@@ -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;
}
}
@@ -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();
@@ -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