mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
Generated
-11
@@ -1,11 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="asm4">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/asm4-all.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/src/asm4-src.zip!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
+1
-1
@@ -187,7 +187,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright 2000-2016 JetBrains s.r.o.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
src/
|
||||
out/
|
||||
@@ -0,0 +1,13 @@
|
||||
Index: org/objectweb/asm/ClassReader.java
|
||||
===================================================================
|
||||
--- org/objectweb/asm/ClassReader.java
|
||||
+++ org/objectweb/asm/ClassReader.java
|
||||
@@ -167,7 +167,7 @@
|
||||
this.b = b;
|
||||
// checks the class version
|
||||
if (readShort(off + 6) > Opcodes.V1_8) {
|
||||
- throw new IllegalArgumentException();
|
||||
+ //[JB: accept any version] throw new IllegalArgumentException();
|
||||
}
|
||||
// parses the constant pool
|
||||
items = new int[readUnsignedShort(off + 8)];
|
||||
@@ -0,0 +1,13 @@
|
||||
Index: org/objectweb/asm/tree/MethodNode.java
|
||||
===================================================================
|
||||
--- org/objectweb/asm/tree/MethodNode.java
|
||||
+++ org/objectweb/asm/tree/MethodNode.java
|
||||
@@ -623,7 +623,7 @@
|
||||
*/
|
||||
protected LabelNode getLabelNode(final Label l) {
|
||||
if (!(l.info instanceof LabelNode)) {
|
||||
- l.info = new LabelNode();
|
||||
+ l.info = new LabelNode(l); //[JB: passing a reference to avoid exceptions in coverage]
|
||||
}
|
||||
return (LabelNode) l.info;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<!--
|
||||
~ Copyright 2000-2016 JetBrains s.r.o.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<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="src.dir" value="${basedir}/src"/>
|
||||
<property name="out.dir" value="${basedir}/out"/>
|
||||
<property name="src.zip" value="${basedir}/asm5-src.zip"/>
|
||||
<property name="out.jar" value="${basedir}/asm-all.jar"/>
|
||||
|
||||
<target name="check">
|
||||
<available file="${asm.src}" type="file" property="asm.src.present"/>
|
||||
<fail message="Please edit the file ${ant.file} and fill in the 'asm.src' property" unless="asm.src.present"/>
|
||||
</target>
|
||||
|
||||
<target name="clean" depends="check">
|
||||
<delete dir="${src.dir}" quiet="true"/>
|
||||
<delete dir="${out.dir}" quiet="true"/>
|
||||
<delete file="${src.zip}" quiet="true"/>
|
||||
<delete file="${out.jar}" quiet="true"/>
|
||||
</target>
|
||||
|
||||
<target name="unpack" depends="clean">
|
||||
<unzip src="${asm.src}" dest="${src.dir}"/>
|
||||
</target>
|
||||
|
||||
<target name="patch" depends="unpack">
|
||||
<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"/>
|
||||
</target>
|
||||
|
||||
<target name="repackage" depends="patch">
|
||||
<replace dir="${src.dir}" token="org.objectweb.asm" value="org.jetbrains.org.objectweb.asm"/>
|
||||
<mkdir dir="${src.dir}/org/jetbrains/org"/>
|
||||
<move file="${src.dir}/org/objectweb" todir="${src.dir}/org/jetbrains/org"/>
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="repackage">
|
||||
<mkdir dir="${out.dir}"/>
|
||||
<javac srcdir="${src.dir}" destdir="${out.dir}" source="1.5" target="1.5" debug="true"/>
|
||||
</target>
|
||||
|
||||
<target name="package" depends="compile">
|
||||
<zip destfile="${src.zip}" basedir="${src.dir}" duplicate="fail"/>
|
||||
<jar destfile="${out.jar}" basedir="${out.dir}" duplicate="fail"/>
|
||||
</target>
|
||||
</project>
|
||||
@@ -49,6 +49,12 @@
|
||||
1.6 => plugins/gradle/lib/gradle-tooling-extension-api.jar
|
||||
1.6 => plugins/gradle/lib/gradle-tooling-extension-impl.jar
|
||||
|
||||
1.6 => plugins/maven/lib/maven-server-api.jar
|
||||
1.6 => plugins/maven/lib/maven2-server-impl.jar
|
||||
1.6 => plugins/maven/lib/maven3-server-common.jar
|
||||
1.6 => plugins/maven/lib/maven30-server-impl.jar
|
||||
1.6 => plugins/maven/lib/maven32-server-impl.jar
|
||||
|
||||
1.4 => plugins/xpath/lib/rt/xslt-rt.jar
|
||||
1.5 => plugins/xslt-debugger/lib/xslt-debugger-engine.jar
|
||||
1.5 => plugins/xslt-debugger/lib/rt/xslt-debugger-engine-impl.jar
|
||||
|
||||
@@ -12,15 +12,15 @@ Text=Create Desktop shortcut
|
||||
[Field 2]
|
||||
Type=checkbox
|
||||
Left=5
|
||||
Right=105
|
||||
Right=70
|
||||
Top=25
|
||||
Bottom=35
|
||||
State=0
|
||||
|
||||
[Field 3]
|
||||
Type=Label
|
||||
Left=115
|
||||
Right=215
|
||||
Left=75
|
||||
Right=140
|
||||
Top=25
|
||||
Bottom=35
|
||||
Text=""
|
||||
|
||||
@@ -706,7 +706,7 @@ binding.setVariable("patchPropertiesFile", { String target, Map args = [:] ->
|
||||
}
|
||||
|
||||
String product_uc = args.product_uc != null ? args.product_uc : p("component.names.product").toUpperCase()
|
||||
String settings_dir = args.system_selector.replaceFirst("\\d+", "")
|
||||
String settings_dir = args.system_selector.replaceFirst("\\d+(\\.\\d+)?", "")
|
||||
ant.replace(file: file) {
|
||||
replacefilter(token: "@@product_uc@@", value: product_uc)
|
||||
replacefilter(token: "@@settings_dir@@", value: settings_dir)
|
||||
|
||||
+2
-2
@@ -35,7 +35,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.roots.*;
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import com.intellij.openapi.roots.ui.configuration.PathUIUtils;
|
||||
import com.intellij.openapi.roots.ui.configuration.LibrarySourceRootDetectorUtil;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.ListSeparator;
|
||||
@@ -305,7 +305,7 @@ public class AttachSourcesNotificationProvider extends EditorNotifications.Provi
|
||||
Library firstLibrary = libraries.get(0).getLibrary();
|
||||
VirtualFile[] roots = firstLibrary != null ? firstLibrary.getFiles(OrderRootType.CLASSES) : VirtualFile.EMPTY_ARRAY;
|
||||
VirtualFile[] candidates = FileChooser.chooseFiles(descriptor, myProject, roots.length == 0 ? null : PathUtil.getLocalFile(roots[0]));
|
||||
final VirtualFile[] files = PathUIUtils.scanAndSelectDetectedJavaSourceRoots(myParentComponent, candidates);
|
||||
final VirtualFile[] files = LibrarySourceRootDetectorUtil.scanAndSelectDetectedJavaSourceRoots(myParentComponent, candidates);
|
||||
if (files.length == 0) {
|
||||
return ActionCallback.REJECTED;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.roots.LibraryOrderEntry;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import com.intellij.openapi.roots.ui.configuration.PathUIUtils;
|
||||
import com.intellij.openapi.roots.ui.configuration.LibrarySourceRootDetectorUtil;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.JarFileSystem;
|
||||
@@ -215,7 +215,7 @@ public class InternetAttachSourceProvider implements AttachSourcesProvider {
|
||||
VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(srcFile);
|
||||
if (jarRoot == null) return;
|
||||
|
||||
VirtualFile[] roots = PathUIUtils.scanAndSelectDetectedJavaSourceRoots(null, new VirtualFile[]{jarRoot});
|
||||
VirtualFile[] roots = LibrarySourceRootDetectorUtil.scanAndSelectDetectedJavaSourceRoots(null, new VirtualFile[]{jarRoot});
|
||||
if (roots.length == 0) {
|
||||
roots = new VirtualFile[]{jarRoot};
|
||||
}
|
||||
|
||||
+16
-6
@@ -34,7 +34,7 @@ import javax.swing.*;
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract class LanguageLevelCombo extends ComboBox {
|
||||
|
||||
private boolean myDefaultWasSelectedBeforeRemoving;
|
||||
private final String myDefaultItem;
|
||||
|
||||
public LanguageLevelCombo(String defaultItem) {
|
||||
@@ -91,18 +91,28 @@ public abstract class LanguageLevelCombo extends ComboBox {
|
||||
|
||||
private void updateDefaultLevel(LanguageLevel newLevel, boolean isDefaultProject) {
|
||||
if (newLevel == null && !isDefaultProject) {
|
||||
if (getSelectedItem() == myDefaultItem) {
|
||||
setSelectedItem(getDefaultLevel());
|
||||
if (isDefaultItemAdded()) {
|
||||
boolean defaultSelected = getSelectedItem() == myDefaultItem;
|
||||
if (defaultSelected) {
|
||||
setSelectedItem(getDefaultLevel());
|
||||
}
|
||||
myDefaultWasSelectedBeforeRemoving = defaultSelected;
|
||||
removeItem(myDefaultItem);
|
||||
}
|
||||
removeItem(myDefaultItem);
|
||||
}
|
||||
else if (!(getItemAt(0) instanceof String)) {
|
||||
else if (!(isDefaultItemAdded())) {
|
||||
addDefaultItem();
|
||||
setSelectedIndex(0);
|
||||
if (myDefaultWasSelectedBeforeRemoving) {
|
||||
setSelectedIndex(0);
|
||||
}
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
private boolean isDefaultItemAdded() {
|
||||
return getItemAt(0) instanceof String;
|
||||
}
|
||||
|
||||
void addDefaultItem() {
|
||||
insertItemAt(myDefaultItem, 0);
|
||||
}
|
||||
|
||||
+2
-2
@@ -23,8 +23,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class JavaSourceRootDetector extends RootDetector {
|
||||
public JavaSourceRootDetector() {
|
||||
public class LibraryJavaSourceRootDetector extends RootDetector {
|
||||
public LibraryJavaSourceRootDetector() {
|
||||
super(OrderRootType.SOURCES, false, "sources");
|
||||
}
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.roots.ui.configuration;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.libraries.ui.OrderRoot;
|
||||
import com.intellij.openapi.roots.libraries.ui.RootDetector;
|
||||
import com.intellij.openapi.roots.libraries.ui.impl.LibraryRootsDetectorImpl;
|
||||
import com.intellij.openapi.roots.libraries.ui.impl.RootDetectionUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This utility class contains utility methods for selecting paths.
|
||||
*
|
||||
* @author Constantine.Plotnikov
|
||||
*/
|
||||
public class LibrarySourceRootDetectorUtil {
|
||||
public static ExtensionPointName<RootDetector> JAVA_SOURCE_ROOT_DETECTOR = ExtensionPointName.create("com.intellij.library.javaSourceRootDetector");
|
||||
|
||||
protected LibrarySourceRootDetectorUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes a candidates for the project root, then scans the candidates and
|
||||
* if multiple candidates or non root source directories are found within some
|
||||
* directories, it shows a dialog that allows selecting or deselecting them.
|
||||
* @param parent a parent parent or project
|
||||
* @param rootCandidates a candidates for roots
|
||||
* @return a array of source folders or empty array if non was selected or dialog was canceled.
|
||||
*/
|
||||
public static VirtualFile[] scanAndSelectDetectedJavaSourceRoots(Component parentComponent, final VirtualFile[] rootCandidates) {
|
||||
final List<OrderRoot> orderRoots = RootDetectionUtil.detectRoots(Arrays.asList(rootCandidates), parentComponent, null,
|
||||
new LibraryRootsDetectorImpl(Arrays.asList(Extensions.getExtensions(JAVA_SOURCE_ROOT_DETECTOR))),
|
||||
new OrderRootType[] {OrderRootType.SOURCES});
|
||||
final List<VirtualFile> result = new ArrayList<VirtualFile>();
|
||||
for (OrderRoot root : orderRoots) {
|
||||
result.add(root.getFile());
|
||||
}
|
||||
return VfsUtil.toVirtualFileArray(result);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,46 +15,12 @@
|
||||
*/
|
||||
package com.intellij.openapi.roots.ui.configuration;
|
||||
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.libraries.ui.OrderRoot;
|
||||
import com.intellij.openapi.roots.libraries.ui.RootDetector;
|
||||
import com.intellij.openapi.roots.libraries.ui.impl.LibraryRootsDetectorImpl;
|
||||
import com.intellij.openapi.roots.libraries.ui.impl.RootDetectionUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This utility class contains utility methods for selecting paths.
|
||||
*
|
||||
* @author Constantine.Plotnikov
|
||||
* @deprecated please use {@link LibrarySourceRootDetectorUtil} directly
|
||||
*/
|
||||
public class PathUIUtils {
|
||||
public static final RootDetector JAVA_SOURCE_ROOT_DETECTOR = new JavaSourceRootDetector();
|
||||
public class PathUIUtils extends LibrarySourceRootDetectorUtil {
|
||||
public static final RootDetector JAVA_SOURCE_ROOT_DETECTOR = new LibraryJavaSourceRootDetector();
|
||||
|
||||
private PathUIUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes a candidates for the project root, then scans the candidates and
|
||||
* if multiple candidates or non root source directories are found within some
|
||||
* directories, it shows a dialog that allows selecting or deselecting them.
|
||||
* @param parent a parent parent or project
|
||||
* @param rootCandidates a candidates for roots
|
||||
* @return a array of source folders or empty array if non was selected or dialog was canceled.
|
||||
*/
|
||||
public static VirtualFile[] scanAndSelectDetectedJavaSourceRoots(Component parentComponent, final VirtualFile[] rootCandidates) {
|
||||
final List<OrderRoot> orderRoots = RootDetectionUtil.detectRoots(Arrays.asList(rootCandidates), parentComponent, null,
|
||||
new LibraryRootsDetectorImpl(Arrays.asList(Extensions.getExtensions(RootDetector.JAVA_SOURCE_ROOT_DETECTOR))),
|
||||
new OrderRootType[] {OrderRootType.SOURCES});
|
||||
final List<VirtualFile> result = new ArrayList<VirtualFile>();
|
||||
for (OrderRoot root : orderRoots) {
|
||||
result.add(root.getFile());
|
||||
}
|
||||
return VfsUtil.toVirtualFileArray(result);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -30,6 +30,7 @@ import com.intellij.openapi.roots.NativeLibraryOrderRootType;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.libraries.ui.*;
|
||||
import com.intellij.openapi.roots.ui.OrderRootTypeUIFactory;
|
||||
import com.intellij.openapi.roots.ui.configuration.LibrarySourceRootDetectorUtil;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -73,7 +74,7 @@ public class DefaultLibraryRootsComponentDescriptor extends LibraryRootsComponen
|
||||
List<RootDetector> results = new ArrayList<>();
|
||||
results.add(new FileTypeBasedRootFilter(OrderRootType.CLASSES, false, StdFileTypes.CLASS, "classes"));
|
||||
results.add(new FileTypeBasedRootFilter(OrderRootType.CLASSES, true, StdFileTypes.CLASS, "jar directory"));
|
||||
results.addAll(Arrays.asList(Extensions.getExtensions(RootDetector.JAVA_SOURCE_ROOT_DETECTOR)));
|
||||
results.addAll(Arrays.asList(Extensions.getExtensions(LibrarySourceRootDetectorUtil.JAVA_SOURCE_ROOT_DETECTOR)));
|
||||
Collections.addAll(results,
|
||||
new FileTypeBasedRootFilter(OrderRootType.SOURCES, true, StdFileTypes.JAVA, "source archive directory"),
|
||||
new JavadocRootDetector(),
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.projectRoots.ui.SdkPathEditor;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.ui.OrderRootTypeUIFactory;
|
||||
import com.intellij.openapi.roots.ui.configuration.PathUIUtils;
|
||||
import com.intellij.openapi.roots.ui.configuration.LibrarySourceRootDetectorUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -61,7 +61,7 @@ public class SourcesOrderRootTypeUIFactory implements OrderRootTypeUIFactory {
|
||||
@Override
|
||||
protected VirtualFile[] adjustAddedFileSet(final Component component, final VirtualFile[] files) {
|
||||
if (mySdk.getSdkType() instanceof JavaSdkType) {
|
||||
return PathUIUtils.scanAndSelectDetectedJavaSourceRoots(component, files);
|
||||
return LibrarySourceRootDetectorUtil.scanAndSelectDetectedJavaSourceRoots(component, files);
|
||||
}
|
||||
return super.adjustAddedFileSet(component, files);
|
||||
}
|
||||
|
||||
@@ -244,6 +244,16 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass {
|
||||
myDefaultConstructor = defaultConstructor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getQualifiedName() {
|
||||
final PsiClass psiClass = getElement();
|
||||
if (psiClass == null) return super.getQualifiedName();
|
||||
final String qName = psiClass.getQualifiedName();
|
||||
if (qName == null) return super.getQualifiedName();
|
||||
return qName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildReferences() {
|
||||
PsiClass psiClass = getElement();
|
||||
|
||||
+36
-9
@@ -53,9 +53,13 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class JavaLineMarkerProvider extends LineMarkerProviderDescriptor {
|
||||
private final DaemonCodeAnalyzerSettings myDaemonSettings;
|
||||
private final EditorColorsManager myColorsManager;
|
||||
protected final DaemonCodeAnalyzerSettings myDaemonSettings;
|
||||
protected final EditorColorsManager myColorsManager;
|
||||
private final Option myLambdaOption = new Option("java.lambda", "Lambda", AllIcons.Gutter.ImplementingFunctionalInterface);
|
||||
private final Option myOverriddenOption = new Option("java.overridden", "Overridden method", AllIcons.Gutter.OverridenMethod);
|
||||
private final Option myImplementedOption = new Option("java.implemented", "Implemented method", AllIcons.Gutter.ImplementedMethod);
|
||||
private final Option myOverridingOption = new Option("java.overriding", "Overriding method", AllIcons.Gutter.OverridingMethod);
|
||||
private final Option myImplementingOption = new Option("java.implementing", "Implementing method", AllIcons.Gutter.ImplementingMethod);
|
||||
|
||||
public JavaLineMarkerProvider(DaemonCodeAnalyzerSettings daemonSettings, EditorColorsManager colorsManager) {
|
||||
myDaemonSettings = daemonSettings;
|
||||
@@ -67,20 +71,29 @@ public class JavaLineMarkerProvider extends LineMarkerProviderDescriptor {
|
||||
public LineMarkerInfo getLineMarkerInfo(@NotNull final PsiElement element) {
|
||||
PsiElement parent;
|
||||
if (element instanceof PsiIdentifier && (parent = element.getParent()) instanceof PsiMethod) {
|
||||
if (!myOverridingOption.isEnabled() && !myImplementingOption.isEnabled()) return null;
|
||||
PsiMethod method = (PsiMethod)parent;
|
||||
MethodSignatureBackedByPsiMethod superSignature = SuperMethodsSearch.search(method, null, true, false).findFirst();
|
||||
if (superSignature != null) {
|
||||
boolean overrides =
|
||||
method.hasModifierProperty(PsiModifier.ABSTRACT) == superSignature.getMethod().hasModifierProperty(PsiModifier.ABSTRACT);
|
||||
|
||||
final Icon icon = overrides ? AllIcons.Gutter.OverridingMethod : AllIcons.Gutter.ImplementingMethod;
|
||||
final Icon icon;
|
||||
if (overrides) {
|
||||
if (!myOverridingOption.isEnabled()) return null;
|
||||
icon = AllIcons.Gutter.OverridingMethod;
|
||||
}
|
||||
else {
|
||||
if (!myImplementingOption.isEnabled()) return null;
|
||||
icon = AllIcons.Gutter.ImplementingMethod;
|
||||
}
|
||||
return createSuperMethodLineMarkerInfo(element, icon, Pass.UPDATE_ALL);
|
||||
}
|
||||
}
|
||||
|
||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(element);
|
||||
final PsiElement firstChild = element.getFirstChild();
|
||||
if (interfaceMethod != null && firstChild != null && LineMarkerSettings.getSettings().isEnabled(myLambdaOption)) {
|
||||
if (interfaceMethod != null && firstChild != null && myLambdaOption.isEnabled()) {
|
||||
return createSuperMethodLineMarkerInfo(firstChild, AllIcons.Gutter.ImplementingFunctionalInterface, Pass.UPDATE_ALL);
|
||||
}
|
||||
|
||||
@@ -216,7 +229,7 @@ public class JavaLineMarkerProvider extends LineMarkerProviderDescriptor {
|
||||
return range;
|
||||
}
|
||||
|
||||
public static void collectInheritingClasses(@NotNull PsiClass aClass,
|
||||
protected void collectInheritingClasses(@NotNull PsiClass aClass,
|
||||
@NotNull Collection<LineMarkerInfo> result,
|
||||
@NotNull Map<PsiClass, PsiClass> subClassCache) {
|
||||
if (aClass.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
@@ -226,7 +239,15 @@ public class JavaLineMarkerProvider extends LineMarkerProviderDescriptor {
|
||||
|
||||
PsiClass subClass = subClassCache.get(aClass);
|
||||
if (subClass != null || FunctionalExpressionSearch.search(aClass).findFirst() != null) {
|
||||
final Icon icon = aClass.isInterface() ? AllIcons.Gutter.ImplementedMethod : AllIcons.Gutter.OverridenMethod;
|
||||
final Icon icon;
|
||||
if (aClass.isInterface()) {
|
||||
if (!myImplementedOption.isEnabled()) return;
|
||||
icon = AllIcons.Gutter.ImplementedMethod;
|
||||
}
|
||||
else {
|
||||
if (!myOverriddenOption.isEnabled()) return;
|
||||
icon = AllIcons.Gutter.OverridenMethod;
|
||||
}
|
||||
PsiElement range = aClass.getNameIdentifier();
|
||||
if (range == null) {
|
||||
range = aClass;
|
||||
@@ -241,7 +262,8 @@ public class JavaLineMarkerProvider extends LineMarkerProviderDescriptor {
|
||||
}
|
||||
}
|
||||
|
||||
private static void collectOverridingMethods(@NotNull final Collection<PsiMethod> methods, @NotNull Collection<LineMarkerInfo> result) {
|
||||
private void collectOverridingMethods(@NotNull final Collection<PsiMethod> methods, @NotNull Collection<LineMarkerInfo> result) {
|
||||
if (!myOverriddenOption.isEnabled() && !myImplementedOption.isEnabled()) return;
|
||||
final Set<PsiMethod> overridden = new HashSet<PsiMethod>();
|
||||
Set<PsiClass> classes = new THashSet<PsiClass>();
|
||||
for (PsiMethod method : methods) {
|
||||
@@ -281,7 +303,12 @@ public class JavaLineMarkerProvider extends LineMarkerProviderDescriptor {
|
||||
for (PsiMethod method : overridden) {
|
||||
ProgressManager.checkCanceled();
|
||||
boolean overrides = !method.hasModifierProperty(PsiModifier.ABSTRACT);
|
||||
|
||||
if (overrides) {
|
||||
if (!myOverriddenOption.isEnabled()) return;
|
||||
}
|
||||
else {
|
||||
if (!myImplementedOption.isEnabled()) return;
|
||||
}
|
||||
PsiElement range = getMethodRange(method);
|
||||
final MarkerType type = MarkerType.OVERRIDDEN_METHOD;
|
||||
final Icon icon = overrides ? AllIcons.Gutter.OverridenMethod : AllIcons.Gutter.ImplementedMethod;
|
||||
@@ -301,7 +328,7 @@ public class JavaLineMarkerProvider extends LineMarkerProviderDescriptor {
|
||||
|
||||
@Override
|
||||
public Option[] getOptions() {
|
||||
return new Option[] {myLambdaOption};
|
||||
return new Option[] {myLambdaOption, myOverriddenOption, myImplementedOption, myOverridingOption, myImplementingOption};
|
||||
}
|
||||
|
||||
private static class ArrowUpLineMarkerInfo extends MergeableLineMarkerInfo<PsiElement> {
|
||||
|
||||
+150
-37
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,8 +16,12 @@
|
||||
package com.intellij.codeInsight.intention.impl;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.CodeInsightUtilCore;
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.codeInsight.template.*;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -29,12 +33,16 @@ import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
|
||||
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SurroundAutoCloseableAction extends PsiElementBaseIntentionAction {
|
||||
@Override
|
||||
@@ -42,16 +50,20 @@ public class SurroundAutoCloseableAction extends PsiElementBaseIntentionAction {
|
||||
if (!element.getLanguage().isKindOf(JavaLanguage.INSTANCE)) return false;
|
||||
if (!PsiUtil.getLanguageLevel(element).isAtLeast(LanguageLevel.JDK_1_7)) return false;
|
||||
|
||||
final PsiLocalVariable variable = PsiTreeUtil.getParentOfType(element, PsiLocalVariable.class);
|
||||
if (variable == null) return false;
|
||||
final PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer == null) return false;
|
||||
final PsiElement declaration = variable.getParent();
|
||||
if (!(declaration instanceof PsiDeclarationStatement)) return false;
|
||||
final PsiElement codeBlock = declaration.getParent();
|
||||
if (!(codeBlock instanceof PsiCodeBlock)) return false;
|
||||
PsiType type = null;
|
||||
|
||||
return InheritanceUtil.isInheritor(variable.getType(), CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE);
|
||||
PsiLocalVariable variable = findVariable(element);
|
||||
if (variable != null) {
|
||||
type = variable.getType();
|
||||
}
|
||||
else {
|
||||
PsiExpression expression = findExpression(element);
|
||||
if (expression != null) {
|
||||
type = expression.getType();
|
||||
}
|
||||
}
|
||||
|
||||
return type != null && InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,35 +72,85 @@ public class SurroundAutoCloseableAction extends PsiElementBaseIntentionAction {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiLocalVariable variable = PsiTreeUtil.getParentOfType(element, PsiLocalVariable.class);
|
||||
if (variable == null) return;
|
||||
final PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer == null) return;
|
||||
final PsiElement declaration = variable.getParent();
|
||||
if (!(declaration instanceof PsiDeclarationStatement)) return;
|
||||
final PsiElement codeBlock = declaration.getParent();
|
||||
if (!(codeBlock instanceof PsiCodeBlock)) return;
|
||||
PsiLocalVariable variable = findVariable(element);
|
||||
if (variable != null) {
|
||||
processVariable(project, editor, variable);
|
||||
}
|
||||
else {
|
||||
PsiExpression expression = findExpression(element);
|
||||
if (expression != null) {
|
||||
processExpression(project, editor, expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final LocalSearchScope scope = new LocalSearchScope(codeBlock);
|
||||
private static PsiLocalVariable findVariable(PsiElement element) {
|
||||
PsiLocalVariable variable = PsiTreeUtil.getParentOfType(element, PsiLocalVariable.class);
|
||||
|
||||
if (variable != null &&
|
||||
variable.getInitializer() != null &&
|
||||
variable.getParent() instanceof PsiDeclarationStatement &&
|
||||
variable.getParent().getParent() instanceof PsiCodeBlock) {
|
||||
return variable;
|
||||
}
|
||||
|
||||
if (variable == null && element instanceof PsiWhiteSpace) {
|
||||
PsiElement sibling = element.getPrevSibling();
|
||||
if (sibling instanceof PsiDeclarationStatement) {
|
||||
PsiElement lastVar = ArrayUtil.getLastElement(((PsiDeclarationStatement)sibling).getDeclaredElements());
|
||||
if (lastVar instanceof PsiLocalVariable) {
|
||||
return (PsiLocalVariable)lastVar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PsiExpression findExpression(PsiElement element) {
|
||||
PsiExpression expression = PsiTreeUtil.getParentOfType(element, PsiExpression.class);
|
||||
|
||||
if (expression != null &&
|
||||
expression.getParent() instanceof PsiExpressionStatement &&
|
||||
expression.getParent().getParent() instanceof PsiCodeBlock) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
if (expression == null && element instanceof PsiWhiteSpace) {
|
||||
PsiElement sibling = element.getPrevSibling();
|
||||
if (sibling instanceof PsiExpressionStatement) {
|
||||
return ((PsiExpressionStatement)sibling).getExpression();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void processVariable(Project project, Editor editor, PsiLocalVariable variable) {
|
||||
PsiExpression initializer = ObjectUtils.assertNotNull(variable.getInitializer());
|
||||
PsiElement declaration = variable.getParent();
|
||||
PsiElement codeBlock = declaration.getParent();
|
||||
|
||||
LocalSearchScope scope = new LocalSearchScope(codeBlock);
|
||||
PsiElement last = null;
|
||||
for (PsiReference reference : ReferencesSearch.search(variable, scope).findAll()) {
|
||||
final PsiElement usage = PsiTreeUtil.findPrevParent(codeBlock, reference.getElement());
|
||||
PsiElement usage = PsiTreeUtil.findPrevParent(codeBlock, reference.getElement());
|
||||
if ((last == null || usage.getTextOffset() > last.getTextOffset())) {
|
||||
last = usage;
|
||||
}
|
||||
}
|
||||
|
||||
final String text = "try (" + variable.getTypeElement().getText() + " " + variable.getName() + " = " + initializer.getText() + ") {}";
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
final PsiTryStatement armStatement = (PsiTryStatement)declaration.replace(factory.createStatementFromText(text, codeBlock));
|
||||
String text = "try (" + variable.getTypeElement().getText() + " " + variable.getName() + " = " + initializer.getText() + ") {}";
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
PsiTryStatement armStatement = (PsiTryStatement)declaration.replace(factory.createStatementFromText(text, codeBlock));
|
||||
|
||||
List<PsiElement> toFormat = null;
|
||||
if (last != null) {
|
||||
toFormat = moveStatements(last, armStatement);
|
||||
}
|
||||
|
||||
final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
|
||||
final PsiElement formattedElement = codeStyleManager.reformat(armStatement);
|
||||
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
|
||||
PsiElement formattedElement = codeStyleManager.reformat(armStatement);
|
||||
if (toFormat != null) {
|
||||
for (PsiElement psiElement : toFormat) {
|
||||
codeStyleManager.reformat(psiElement);
|
||||
@@ -96,9 +158,9 @@ public class SurroundAutoCloseableAction extends PsiElementBaseIntentionAction {
|
||||
}
|
||||
|
||||
if (last == null) {
|
||||
final PsiCodeBlock tryBlock = ((PsiTryStatement)formattedElement).getTryBlock();
|
||||
PsiCodeBlock tryBlock = ((PsiTryStatement)formattedElement).getTryBlock();
|
||||
if (tryBlock != null) {
|
||||
final PsiJavaToken brace = tryBlock.getLBrace();
|
||||
PsiJavaToken brace = tryBlock.getLBrace();
|
||||
if (brace != null) {
|
||||
editor.getCaretModel().moveToOffset(brace.getTextOffset() + 1);
|
||||
}
|
||||
@@ -110,8 +172,9 @@ public class SurroundAutoCloseableAction extends PsiElementBaseIntentionAction {
|
||||
PsiCodeBlock tryBlock = statement.getTryBlock();
|
||||
assert tryBlock != null : statement.getText();
|
||||
PsiElement parent = statement.getParent();
|
||||
LocalSearchScope scope = new LocalSearchScope(parent);
|
||||
|
||||
List<PsiElement> toFormat = new SmartList<PsiElement>();
|
||||
List<PsiElement> toFormat = new SmartList<>();
|
||||
PsiElement stopAt = last.getNextSibling();
|
||||
|
||||
PsiElement i = statement.getNextSibling();
|
||||
@@ -125,13 +188,8 @@ public class SurroundAutoCloseableAction extends PsiElementBaseIntentionAction {
|
||||
for (PsiElement declared : ((PsiDeclarationStatement)child).getDeclaredElements()) {
|
||||
if (!(declared instanceof PsiLocalVariable)) continue;
|
||||
|
||||
final int endOffset = last.getTextRange().getEndOffset();
|
||||
boolean contained = ReferencesSearch.search(declared, new LocalSearchScope(parent)).forEach(new Processor<PsiReference>() {
|
||||
@Override
|
||||
public boolean process(PsiReference ref) {
|
||||
return ref.getElement().getTextOffset() <= endOffset;
|
||||
}
|
||||
});
|
||||
int endOffset = last.getTextRange().getEndOffset();
|
||||
boolean contained = ReferencesSearch.search(declared, scope).forEach(ref -> ref.getElement().getTextOffset() <= endOffset);
|
||||
|
||||
if (!contained) {
|
||||
PsiLocalVariable var = (PsiLocalVariable)declared;
|
||||
@@ -163,6 +221,38 @@ public class SurroundAutoCloseableAction extends PsiElementBaseIntentionAction {
|
||||
return toFormat;
|
||||
}
|
||||
|
||||
private static void processExpression(Project project, Editor editor, PsiExpression expression) {
|
||||
PsiType type = ObjectUtils.assertNotNull(expression.getType());
|
||||
PsiElement statement = expression.getParent();
|
||||
PsiElement codeBlock = statement.getParent();
|
||||
|
||||
String text = "try (" + type.getCanonicalText(true) + " r = " + expression.getText() + ") {}";
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
PsiTryStatement tryStatement = (PsiTryStatement)statement.replace(factory.createStatementFromText(text, codeBlock));
|
||||
|
||||
tryStatement = (PsiTryStatement)CodeStyleManager.getInstance(project).reformat(tryStatement);
|
||||
|
||||
tryStatement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(tryStatement);
|
||||
|
||||
PsiResourceList resourceList = tryStatement.getResourceList();
|
||||
if (resourceList != null) {
|
||||
PsiResourceVariable var = (PsiResourceVariable)resourceList.iterator().next();
|
||||
PsiIdentifier id = var.getNameIdentifier();
|
||||
PsiExpression initializer = var.getInitializer();
|
||||
if (id != null && initializer != null) {
|
||||
type = initializer.getType();
|
||||
String[] names = IntroduceVariableBase.getSuggestedName(type, initializer).names;
|
||||
PsiType[] types = Stream.of(new TypeSelectorManagerImpl(project, type, initializer, PsiExpression.EMPTY_ARRAY).getTypesForAll())
|
||||
.filter(t -> InheritanceUtil.isInheritor(t, CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE))
|
||||
.toArray(PsiType[]::new);
|
||||
TemplateBuilder builder = TemplateBuilderFactory.getInstance().createTemplateBuilder(var);
|
||||
builder.replaceElement(id, new NamesExpression(names));
|
||||
builder.replaceElement(var.getTypeElement(), new TypeExpression(project, types));
|
||||
builder.run(editor, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
@@ -174,4 +264,27 @@ public class SurroundAutoCloseableAction extends PsiElementBaseIntentionAction {
|
||||
public String getText() {
|
||||
return getFamilyName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class NamesExpression extends Expression {
|
||||
private final String[] myNames;
|
||||
|
||||
public NamesExpression(String[] names) {
|
||||
myNames = names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result calculateResult(ExpressionContext context) {
|
||||
return calculateQuickResult(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result calculateQuickResult(ExpressionContext context) {
|
||||
return new TextResult(myNames[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LookupElement[] calculateLookupItems(ExpressionContext context) {
|
||||
return Stream.of(myNames).map(LookupElementBuilder::create).toArray(LookupElement[]::new);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1728,6 +1728,22 @@ public class ExtractMethodProcessor implements MatchProvider {
|
||||
myExtractedMethod = suggester.getExtractedMethod();
|
||||
myMethodCall = suggester.getMethodCall();
|
||||
myVariableDatum = suggester.getVariableData();
|
||||
|
||||
final List<PsiVariable> outputVariables = new ArrayList<>();
|
||||
for (PsiReturnStatement statement : PsiUtil.findReturnStatements(myExtractedMethod)) {
|
||||
final PsiExpression returnValue = statement.getReturnValue();
|
||||
if (returnValue instanceof PsiReferenceExpression) {
|
||||
final PsiElement resolve = ((PsiReferenceExpression)returnValue).resolve();
|
||||
if (resolve instanceof PsiLocalVariable) {
|
||||
outputVariables.add((PsiVariable)resolve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (outputVariables.size() == 1) {
|
||||
myOutputVariable = outputVariables.get(0);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -334,6 +334,12 @@ public class ExtractMethodSignatureSuggester {
|
||||
for (PsiParameter parameter : parameters) {
|
||||
uniqueNameGenerator.addExistingName(parameter.getName());
|
||||
}
|
||||
|
||||
SyntaxTraverser.psiTraverser().withRoot(myExtractedMethod.getBody())
|
||||
.filter(element -> element instanceof PsiVariable)
|
||||
.forEach(element -> uniqueNameGenerator.addExistingName(((PsiVariable)element).getName()));
|
||||
|
||||
|
||||
final THashMap<PsiExpression, String> unique = new THashMap<PsiExpression, String>(ourEquivalenceStrategy);
|
||||
final Map<PsiExpression, String> replacement = new HashMap<PsiExpression, String>();
|
||||
for (PsiExpression expr : exprs) {
|
||||
|
||||
@@ -256,6 +256,27 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> findConflicts(PsiElement element, PsiElement[] elements, UsageInfo[] usages) {
|
||||
String methodRefFound = null;
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode() && (element instanceof PsiMethod || element instanceof PsiParameter)) {
|
||||
for (UsageInfo usage : usages) {
|
||||
final PsiElement refElement = usage.getElement();
|
||||
if (refElement instanceof PsiMethodReferenceExpression) {
|
||||
methodRefFound = RefactoringBundle.message("expand.method.reference.warning");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (methodRefFound != null) {
|
||||
Collection<String> result = new ArrayList<>();
|
||||
result.add(methodRefFound);
|
||||
result.addAll(super.findConflicts(element, elements, usages));
|
||||
return result;
|
||||
}
|
||||
return super.findConflicts(element, elements, usages);
|
||||
}
|
||||
|
||||
public Collection<String> findConflicts(@NotNull final PsiElement element, @NotNull final PsiElement[] allElementsToDelete) {
|
||||
if (element instanceof PsiMethod) {
|
||||
final PsiClass containingClass = ((PsiMethod)element).getContainingClass();
|
||||
|
||||
@@ -17,6 +17,8 @@ package com.intellij.psi;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.RecursionGuard;
|
||||
import com.intellij.openapi.util.RecursionManager;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
@@ -35,6 +37,7 @@ import java.util.*;
|
||||
* Date: 7/17/12
|
||||
*/
|
||||
public class LambdaUtil {
|
||||
public static final RecursionGuard ourParameterGuard = RecursionManager.createGuard("lambdaParameterGuard");
|
||||
public static ThreadLocal<Map<PsiElement, PsiType>> ourFunctionTypes = new ThreadLocal<Map<PsiElement, PsiType>>();
|
||||
private static final Logger LOG = Logger.getInstance("#" + LambdaUtil.class.getName());
|
||||
|
||||
@@ -667,6 +670,10 @@ public class LambdaUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isLambdaParameterCheck() {
|
||||
return !ourParameterGuard.currentStack().isEmpty();
|
||||
}
|
||||
|
||||
public static class TypeParamsChecker extends PsiTypeVisitor<Boolean> {
|
||||
private PsiMethod myMethod;
|
||||
private final PsiClass myClass;
|
||||
|
||||
@@ -294,7 +294,9 @@ public class MethodCandidateInfo extends CandidateInfo{
|
||||
if (!stackStamp.mayCacheNow() ||
|
||||
isOverloadCheck() ||
|
||||
!includeReturnConstraint && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) ||
|
||||
getMarkerList() != null && PsiResolveHelper.ourGraphGuard.currentStack().contains(getMarkerList().getParent())) {
|
||||
getMarkerList() != null && PsiResolveHelper.ourGraphGuard.currentStack().contains(getMarkerList().getParent()) ||
|
||||
LambdaUtil.isLambdaParameterCheck()
|
||||
) {
|
||||
return inferredSubstitutor;
|
||||
}
|
||||
|
||||
|
||||
@@ -435,7 +435,7 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
|
||||
public PsiType[] getArgumentTypes() {
|
||||
if (myExpressionTypes == null) {
|
||||
final PsiType[] expressionTypes = argumentList.getExpressionTypes();
|
||||
if (MethodCandidateInfo.isOverloadCheck()) {
|
||||
if (MethodCandidateInfo.isOverloadCheck() || LambdaUtil.isLambdaParameterCheck()) {
|
||||
return expressionTypes;
|
||||
}
|
||||
myExpressionTypes = expressionTypes;
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.navigation.ItemPresentation;
|
||||
import com.intellij.navigation.ItemPresentationProviders;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.CheckUtil;
|
||||
import com.intellij.psi.impl.ElementPresentationUtil;
|
||||
@@ -67,8 +68,14 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple
|
||||
if (parameterIndex > -1) {
|
||||
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(param, PsiLambdaExpression.class);
|
||||
if (lambdaExpression != null) {
|
||||
|
||||
PsiType type = FunctionalInterfaceParameterizationUtil.getGroundTargetType(LambdaUtil.getFunctionalInterfaceType(lambdaExpression, true), lambdaExpression);
|
||||
final PsiType functionalInterfaceType = LambdaUtil.ourParameterGuard.doPreventingRecursion(param, false,
|
||||
new Computable<PsiType>() {
|
||||
@Override
|
||||
public PsiType compute() {
|
||||
return LambdaUtil.getFunctionalInterfaceType(lambdaExpression, true);
|
||||
}
|
||||
});
|
||||
PsiType type = FunctionalInterfaceParameterizationUtil.getGroundTargetType(functionalInterfaceType, lambdaExpression);
|
||||
if (type instanceof PsiIntersectionType) {
|
||||
final PsiType[] conjuncts = ((PsiIntersectionType)type).getConjuncts();
|
||||
for (PsiType conjunct : conjuncts) {
|
||||
|
||||
@@ -90,7 +90,7 @@ public class JavaResolveCache {
|
||||
}
|
||||
|
||||
//cache standalone expression types as they do not depend on the context
|
||||
final boolean isOverloadCheck = MethodCandidateInfo.isOverloadCheck();
|
||||
final boolean isOverloadCheck = MethodCandidateInfo.isOverloadCheck() || LambdaUtil.isLambdaParameterCheck();
|
||||
if (isOverloadCheck && PsiPolyExpressionUtil.isPolyExpression(expr)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
+83
-45
@@ -361,11 +361,13 @@ public class InferenceSession {
|
||||
|
||||
if (parameters != null && args != null && !isOverloadCheck()) {
|
||||
final Set<ConstraintFormula> additionalConstraints = new LinkedHashSet<ConstraintFormula>();
|
||||
final HashSet<ConstraintFormula> ignoredConstraints = new HashSet<ConstraintFormula>();
|
||||
if (parameters.length > 0) {
|
||||
collectAdditionalConstraints(parameters, args, properties.getMethod(), mySiteSubstitutor, additionalConstraints, properties.isVarargs(), initialSubstitutor);
|
||||
collectAdditionalConstraints(parameters, args, properties.getMethod(), mySiteSubstitutor, additionalConstraints,
|
||||
ignoredConstraints, properties.isVarargs(), initialSubstitutor);
|
||||
}
|
||||
|
||||
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints)) {
|
||||
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints, ignoredConstraints)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -416,21 +418,29 @@ public class InferenceSession {
|
||||
PsiMethod parentMethod,
|
||||
PsiSubstitutor siteSubstitutor,
|
||||
Set<ConstraintFormula> additionalConstraints,
|
||||
Set<ConstraintFormula> ignoredConstraints,
|
||||
boolean varargs,
|
||||
PsiSubstitutor initialSubstitutor) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
final PsiExpression arg = PsiUtil.skipParenthesizedExprDown(args[i]);
|
||||
if (arg != null) {
|
||||
if (MethodCandidateInfo.isOverloadCheck() && arg instanceof PsiLambdaExpression) {
|
||||
for (Object expr : MethodCandidateInfo.ourOverloadGuard.currentStack()) {
|
||||
if (PsiTreeUtil.getParentOfType((PsiElement)expr, PsiLambdaExpression.class) == arg) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
final PsiSubstitutor nestedSubstitutor = myInferenceSessionContainer.findNestedSubstitutor(arg, myInferenceSubstitution);
|
||||
final PsiType parameterType = nestedSubstitutor.substitute(getParameterType(parameters, i, siteSubstitutor, varargs));
|
||||
if (!isPertinentToApplicability(arg, parentMethod)) {
|
||||
if (arg instanceof PsiLambdaExpression) {
|
||||
for (Object expr : MethodCandidateInfo.ourOverloadGuard.currentStack()) {
|
||||
if (PsiTreeUtil.getParentOfType((PsiElement)expr, PsiLambdaExpression.class) == arg) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (Object expr : LambdaUtil.ourParameterGuard.currentStack()) {
|
||||
if (expr instanceof PsiParameter && ((PsiParameter)expr).getDeclarationScope() == arg) {
|
||||
ignoredConstraints.add(new ExpressionCompatibilityConstraint(arg, parameterType));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
additionalConstraints.add(new ExpressionCompatibilityConstraint(arg, parameterType));
|
||||
}
|
||||
additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(arg, parameterType));
|
||||
@@ -439,12 +449,12 @@ public class InferenceSession {
|
||||
//the set contains all constraint formulas that would appear in the set C when determining the poly expression's invocation type.
|
||||
final PsiMethod calledMethod = getCalledMethod((PsiCall)arg);
|
||||
if (calledMethod != null && PsiPolyExpressionUtil.isMethodCallPolyExpression(arg, calledMethod)) {
|
||||
collectAdditionalConstraints(additionalConstraints, (PsiCall)arg, initialSubstitutor);
|
||||
collectAdditionalConstraints(additionalConstraints, ignoredConstraints, (PsiCall)arg, initialSubstitutor);
|
||||
}
|
||||
}
|
||||
else if (arg instanceof PsiLambdaExpression &&
|
||||
isPertinentToApplicability(arg, parentMethod)) {
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)arg, parameterType,
|
||||
collectLambdaReturnExpression(additionalConstraints, ignoredConstraints, (PsiLambdaExpression)arg, parameterType,
|
||||
!isProperType(initialSubstitutor.substitute(parameterType)),
|
||||
initialSubstitutor);
|
||||
}
|
||||
@@ -472,19 +482,22 @@ public class InferenceSession {
|
||||
}
|
||||
|
||||
private void collectLambdaReturnExpression(Set<ConstraintFormula> additionalConstraints,
|
||||
Set<ConstraintFormula> ignoredConstraints,
|
||||
PsiLambdaExpression lambdaExpression,
|
||||
PsiType parameterType,
|
||||
boolean addConstraint, PsiSubstitutor initialSubstitutor) {
|
||||
boolean addConstraint,
|
||||
PsiSubstitutor initialSubstitutor) {
|
||||
final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(parameterType);
|
||||
if (interfaceReturnType != null) {
|
||||
final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions(lambdaExpression);
|
||||
for (PsiExpression returnExpression : returnExpressions) {
|
||||
processReturnExpression(additionalConstraints, returnExpression, interfaceReturnType, addConstraint, initialSubstitutor);
|
||||
processReturnExpression(additionalConstraints, ignoredConstraints, returnExpression, interfaceReturnType, addConstraint, initialSubstitutor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processReturnExpression(Set<ConstraintFormula> additionalConstraints,
|
||||
Set<ConstraintFormula> ignoredConstraints,
|
||||
PsiExpression returnExpression,
|
||||
PsiType functionalType,
|
||||
boolean addConstraint,
|
||||
@@ -493,7 +506,7 @@ public class InferenceSession {
|
||||
if (addConstraint) {
|
||||
final PsiMethod calledMethod = getCalledMethod((PsiCallExpression)returnExpression);
|
||||
if (calledMethod != null && PsiPolyExpressionUtil.isMethodCallPolyExpression(returnExpression, calledMethod)) {
|
||||
collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)returnExpression, initialSubstitutor);
|
||||
collectAdditionalConstraints(additionalConstraints, ignoredConstraints, (PsiCallExpression)returnExpression, initialSubstitutor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -501,19 +514,20 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
else if (returnExpression instanceof PsiParenthesizedExpression) {
|
||||
processReturnExpression(additionalConstraints, ((PsiParenthesizedExpression)returnExpression).getExpression(), functionalType, addConstraint, initialSubstitutor);
|
||||
processReturnExpression(additionalConstraints, ignoredConstraints, ((PsiParenthesizedExpression)returnExpression).getExpression(), functionalType, addConstraint, initialSubstitutor);
|
||||
}
|
||||
else if (returnExpression instanceof PsiConditionalExpression) {
|
||||
processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getThenExpression(), functionalType, addConstraint, initialSubstitutor);
|
||||
processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getElseExpression(), functionalType, addConstraint, initialSubstitutor);
|
||||
processReturnExpression(additionalConstraints, ignoredConstraints, ((PsiConditionalExpression)returnExpression).getThenExpression(), functionalType, addConstraint, initialSubstitutor);
|
||||
processReturnExpression(additionalConstraints, ignoredConstraints, ((PsiConditionalExpression)returnExpression).getElseExpression(), functionalType, addConstraint, initialSubstitutor);
|
||||
}
|
||||
else if (returnExpression instanceof PsiLambdaExpression) {
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)returnExpression, functionalType, myErased, initialSubstitutor);
|
||||
collectLambdaReturnExpression(additionalConstraints, ignoredConstraints, (PsiLambdaExpression)returnExpression, functionalType, myErased, initialSubstitutor);
|
||||
}
|
||||
}
|
||||
|
||||
private void collectAdditionalConstraints(final Set<ConstraintFormula> additionalConstraints,
|
||||
final PsiCall callExpression,
|
||||
final Set<ConstraintFormula> ignoredConstraints,
|
||||
final PsiCall callExpression,
|
||||
PsiSubstitutor initialSubstitutor) {
|
||||
PsiExpressionList argumentList = callExpression.getArgumentList();
|
||||
if (argumentList != null) {
|
||||
@@ -524,7 +538,8 @@ public class InferenceSession {
|
||||
final PsiExpression[] newArgs = argumentList.getExpressions();
|
||||
final PsiParameter[] newParams = method.getParameterList().getParameters();
|
||||
if (newParams.length > 0) {
|
||||
collectAdditionalConstraints(newParams, newArgs, method, chooseSiteSubstitutor(properties, result, method), additionalConstraints, chooseVarargsMode(properties, result), initialSubstitutor);
|
||||
collectAdditionalConstraints(newParams, newArgs, method, chooseSiteSubstitutor(properties, result, method), additionalConstraints,
|
||||
ignoredConstraints, chooseVarargsMode(properties, result), initialSubstitutor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1290,7 +1305,7 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean proceedWithAdditionalConstraints(Set<ConstraintFormula> additionalConstraints) {
|
||||
private boolean proceedWithAdditionalConstraints(Set<ConstraintFormula> additionalConstraints, Set<ConstraintFormula> ignoredConstraints) {
|
||||
//empty substitutor should be used to resolve input variables:
|
||||
//all types in additional constraints are already substituted during collecting phase,
|
||||
//recursive site substitutors (T -> List<T>) would make additional constraints work with multiple times substituted types, which is incorrect.
|
||||
@@ -1300,7 +1315,7 @@ public class InferenceSession {
|
||||
|
||||
while (!additionalConstraints.isEmpty()) {
|
||||
//extract subset of constraints
|
||||
final Set<ConstraintFormula> subset = buildSubset(additionalConstraints);
|
||||
final Set<ConstraintFormula> subset = buildSubset(additionalConstraints, ignoredConstraints);
|
||||
|
||||
//collect all input variables of selection
|
||||
final Set<InferenceVariable> varsToResolve = new LinkedHashSet<InferenceVariable>();
|
||||
@@ -1312,7 +1327,7 @@ public class InferenceSession {
|
||||
|
||||
final PsiSubstitutor substitutor = resolveSubsetOrdered(varsToResolve, siteSubstitutor);
|
||||
for (ConstraintFormula formula : subset) {
|
||||
if (!processOneConstraint(formula, additionalConstraints, substitutor)) return false;
|
||||
if (!processOneConstraint(formula, additionalConstraints, substitutor, ignoredConstraints)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -1329,8 +1344,9 @@ public class InferenceSession {
|
||||
}
|
||||
|
||||
private boolean processOneConstraint(ConstraintFormula formula,
|
||||
Set<ConstraintFormula> additionalConstraints,
|
||||
PsiSubstitutor substitutor) {
|
||||
Set<ConstraintFormula> additionalConstraints,
|
||||
PsiSubstitutor substitutor,
|
||||
Set<ConstraintFormula> ignoredConstraints) {
|
||||
|
||||
if (myContext instanceof PsiCall) {
|
||||
PsiExpressionList argumentList = ((PsiCall)myContext).getArgumentList();
|
||||
@@ -1348,27 +1364,20 @@ public class InferenceSession {
|
||||
if (formula instanceof ExpressionCompatibilityConstraint) {
|
||||
PsiExpression expression = ((ExpressionCompatibilityConstraint)formula).getExpression();
|
||||
if (expression instanceof PsiLambdaExpression) {
|
||||
PsiType parameterType = FunctionalInterfaceParameterizationUtil.getGroundTargetType(((ExpressionCompatibilityConstraint)formula).getT(),
|
||||
(PsiLambdaExpression)expression);
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)expression, parameterType, !isProperType(parameterType), substitutor);
|
||||
PsiType parameterType = FunctionalInterfaceParameterizationUtil.getGroundTargetType(((ExpressionCompatibilityConstraint)formula).getT(), (PsiLambdaExpression)expression);
|
||||
collectLambdaReturnExpression(additionalConstraints, ignoredConstraints, (PsiLambdaExpression)expression, parameterType, !isProperType(parameterType), substitutor);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Set<ConstraintFormula> buildSubset(final Set<ConstraintFormula> additionalConstraints) {
|
||||
private Set<ConstraintFormula> buildSubset(final Set<ConstraintFormula> additionalConstraints,
|
||||
final Set<ConstraintFormula> ignoredConstraints) {
|
||||
|
||||
final Set<InferenceVariable> outputVariables = getOutputVariables(additionalConstraints);
|
||||
final Set<InferenceVariable> ignoredOutputVariables = getOutputVariables(ignoredConstraints);
|
||||
|
||||
Set<ConstraintFormula> subset = new LinkedHashSet<ConstraintFormula>();
|
||||
final Set<InferenceVariable> outputVariables = new HashSet<InferenceVariable>();
|
||||
for (ConstraintFormula constraint : additionalConstraints) {
|
||||
if (constraint instanceof InputOutputConstraintFormula) {
|
||||
final Set<InferenceVariable> inputVariables = ((InputOutputConstraintFormula)constraint).getInputVariables(this);
|
||||
final Set<InferenceVariable> outputVars = ((InputOutputConstraintFormula)constraint).getOutputVariables(inputVariables, this);
|
||||
if (outputVars != null) {
|
||||
outputVariables.addAll(outputVars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<ConstraintFormula> noInputVariables = new LinkedHashSet<ConstraintFormula>();
|
||||
for (ConstraintFormula constraint : additionalConstraints) {
|
||||
@@ -1382,11 +1391,13 @@ public class InferenceSession {
|
||||
final Set<InferenceVariable> dependencies = inputVariable.getDependencies(this);
|
||||
dependencies.add(inputVariable);
|
||||
if (!hasCapture(inputVariable)) {
|
||||
for (InferenceVariable outputVariable : outputVariables) {
|
||||
if (ContainerUtil.intersects(outputVariable.getDependencies(this), dependencies)) {
|
||||
dependsOnOutput = true;
|
||||
break;
|
||||
}
|
||||
if (dependsOnOutput(ignoredOutputVariables, dependencies)) {
|
||||
dependsOnOutput = true;
|
||||
ignoredConstraints.add(constraint);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
dependsOnOutput = dependsOnOutput(outputVariables, dependencies);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1414,7 +1425,10 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
if (subset.isEmpty()) {
|
||||
subset.add(additionalConstraints.iterator().next()); //todo choose one constraint
|
||||
additionalConstraints.removeAll(ignoredConstraints);
|
||||
if (!additionalConstraints.isEmpty()) {
|
||||
subset.add(additionalConstraints.iterator().next()); //todo choose one constraint
|
||||
}
|
||||
}
|
||||
|
||||
if (!noInputVariables.isEmpty()) {
|
||||
@@ -1425,6 +1439,30 @@ public class InferenceSession {
|
||||
return subset;
|
||||
}
|
||||
|
||||
private boolean dependsOnOutput(Set<InferenceVariable> outputVariables, Set<InferenceVariable> dependencies) {
|
||||
for (InferenceVariable outputVariable : outputVariables) {
|
||||
if (ContainerUtil.intersects(outputVariable.getDependencies(this), dependencies)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<InferenceVariable> getOutputVariables(Set<ConstraintFormula> constraintFormulas) {
|
||||
final Set<InferenceVariable> outputVariables = new HashSet<InferenceVariable>();
|
||||
for (ConstraintFormula constraint : constraintFormulas) {
|
||||
if (constraint instanceof InputOutputConstraintFormula) {
|
||||
final Set<InferenceVariable> inputVariables = ((InputOutputConstraintFormula)constraint).getInputVariables(this);
|
||||
final Set<InferenceVariable> outputVars = ((InputOutputConstraintFormula)constraint).getOutputVariables(inputVariables, this);
|
||||
if (outputVars != null) {
|
||||
outputVariables.addAll(outputVars);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outputVariables;
|
||||
}
|
||||
|
||||
public PsiSubstitutor collectApplicabilityConstraints(final PsiMethodReferenceExpression reference,
|
||||
final MethodCandidateInfo candidateInfo,
|
||||
final PsiType functionalInterfaceType) {
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ public class InferenceSessionContainer {
|
||||
if (topLevelCall != null) {
|
||||
|
||||
final InferenceSession session;
|
||||
if (MethodCandidateInfo.isOverloadCheck() || !PsiDiamondType.ourDiamondGuard.currentStack().isEmpty()) {
|
||||
if (MethodCandidateInfo.isOverloadCheck() || !PsiDiamondType.ourDiamondGuard.currentStack().isEmpty() || LambdaUtil.isLambdaParameterCheck()) {
|
||||
session = startTopLevelInference(topLevelCall);
|
||||
}
|
||||
else {
|
||||
|
||||
+5
-5
@@ -134,9 +134,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
|
||||
if (method != null && !method.isConstructor()) {
|
||||
returnType = method.getReturnType();
|
||||
if (returnType != null) {
|
||||
typeParams = method.getTypeParameters();
|
||||
}
|
||||
typeParams = method.getTypeParameters();
|
||||
}
|
||||
else if (resolveResult != null) {
|
||||
final PsiClass psiClass = method != null ? method.getContainingClass() : (PsiClass)resolveResult.getElement();
|
||||
@@ -162,7 +160,9 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
return callSession;
|
||||
}
|
||||
|
||||
callSession.registerReturnTypeConstraints(siteSubstitutor.substitute(returnType), targetType);
|
||||
if (returnType != null) {
|
||||
callSession.registerReturnTypeConstraints(siteSubstitutor.substitute(returnType), targetType);
|
||||
}
|
||||
if (callSession.repeatInferencePhases()) {
|
||||
return callSession;
|
||||
}
|
||||
@@ -175,8 +175,8 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
session.registerIncompatibleErrorMessage(message);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
|
||||
myArgumentsList.getText() + "; " +
|
||||
"file=" + (method == null ? "<unknown>" : method.getContainingFile()));
|
||||
}
|
||||
return MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(myArgumentsList, true, new Computable<CandidateInfo>() {
|
||||
return MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(myArgumentsList, false, new Computable<CandidateInfo>() {
|
||||
@Override
|
||||
public CandidateInfo compute() {
|
||||
return guardedOverloadResolution(conflicts);
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ public class MethodCandidatesProcessor extends MethodsProcessor{
|
||||
public PsiType[] getArgumentTypes() {
|
||||
if (myExpressionTypes == null && argumentList != null) {
|
||||
final PsiType[] expressionTypes = getExpressionTypes(argumentList);
|
||||
if (MethodCandidateInfo.isOverloadCheck()) {
|
||||
if (MethodCandidateInfo.isOverloadCheck() || LambdaUtil.isLambdaParameterCheck()) {
|
||||
return expressionTypes;
|
||||
}
|
||||
myExpressionTypes = expressionTypes;
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class Test {
|
||||
<K> void foo(Function<String, K> f1) {}
|
||||
|
||||
<T> Stream<T> bar(T ts) {
|
||||
return null;
|
||||
}
|
||||
|
||||
void f(){
|
||||
foo(y -> bar(y.to<caret>String()).map(a -> a.length()));
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
class StreamMainSimplified {
|
||||
public static void main(Optional<Map.Entry<Integer, String>> first) {
|
||||
String s1 = first.map((e) -> e.getV<caret>alue()).orElse("").substring(9);
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -3,8 +3,8 @@ import java.util.*;
|
||||
class Main {
|
||||
|
||||
void foo(List<Integer> list) {
|
||||
bar(list, i -> i.intValue(), i -> i.<error descr="Cannot resolve method 'unknown()'">unknown</error>());
|
||||
bar1(list, i -> i.intValue(), i -> i.<error descr="Cannot resolve method 'unknown()'">unknown</error>());
|
||||
bar(list, i -> <error descr="Bad return type in lambda expression: int cannot be converted to S_OUT">i.intValue()</error>, i -> i.<error descr="Cannot resolve method 'unknown()'">unknown</error>());
|
||||
bar1(list, i -> <error descr="Bad return type in lambda expression: int cannot be converted to S_OUT">i.intValue()</error>, i -> i.<error descr="Cannot resolve method 'unknown()'">unknown</error>());
|
||||
}
|
||||
|
||||
<U, S_IN, S_OUT, R> R bar(List<S_IN> list,
|
||||
|
||||
+9
@@ -36,3 +36,12 @@ final class Collectors {
|
||||
downstream.characteristics().toArray(new Collector.Characteristics[downstream.characteristics().size()]));
|
||||
}
|
||||
}
|
||||
|
||||
class SimplifiedTest {
|
||||
|
||||
public static void a(Stream<Integer> classifier) {
|
||||
flatMapping(classifier.map(k -> new AbstractMap.SimpleEntry<Integer, String>(k,k.toString())), Map.Entry::getKey);
|
||||
}
|
||||
|
||||
public static <U, R> void flatMapping(Stream<U> stream, Function<U, R> downstream) {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.io.*;
|
||||
|
||||
class C {
|
||||
void m(File file) throws IOException {
|
||||
<caret>new FileInputStream(file);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.io.*;
|
||||
|
||||
class C {
|
||||
void m(File file) throws IOException {
|
||||
new FileInputStream(file)<caret>
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import java.io.*;
|
||||
|
||||
class C {
|
||||
void m(File file) throws IOException {
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import java.io.*;
|
||||
|
||||
class C {
|
||||
void m(File file) throws IOException {
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
||||
class C {
|
||||
public void read(URLConnection connection) {
|
||||
InputStream stream = connection.getInputStream();<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
||||
class C {
|
||||
public void read(URLConnection connection) {
|
||||
try (InputStream stream = connection.getInputStream()) {<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
class Test {
|
||||
|
||||
private BigDecimal getRevenue() {
|
||||
<selection>final String query = createNamedQuery("revenues");
|
||||
String revenues = "";
|
||||
final String revenue;
|
||||
revenue = "a";
|
||||
</selection>
|
||||
return revenue;
|
||||
}
|
||||
|
||||
public BigDecimal getExpense() {
|
||||
final String query = createNamedQuery("expenses");
|
||||
String expenses = "";
|
||||
final String expense;
|
||||
expense = "a";
|
||||
|
||||
return expense;
|
||||
}
|
||||
|
||||
private String createNamedQuery(String expenses) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class Test {
|
||||
|
||||
private BigDecimal getRevenue() {
|
||||
final String revenue = newMethod("revenues");
|
||||
|
||||
return revenue;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String newMethod(String revenues2) {
|
||||
final String query = createNamedQuery(revenues2);
|
||||
String revenues = "";
|
||||
final String revenue;
|
||||
revenue = "a";
|
||||
return revenue;
|
||||
}
|
||||
|
||||
public BigDecimal getExpense() {
|
||||
final String expense = newMethod("expenses");
|
||||
|
||||
return expense;
|
||||
}
|
||||
|
||||
private String createNamedQuery(String expenses) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+12
-12
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.projectRoots.JavaSdkVersion;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
@@ -419,18 +420,17 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(tooltips.contains("<html><body><table border=0><tr><td>" +
|
||||
"<b>identity( ) </b></td><td colspan=1>in <b>Function</b> cannot be applied</td></tr><tr><td>to</td><td><b>()</b> " +
|
||||
|
||||
"</td></tr></table><br/>" +
|
||||
"reason: no instance(s) of type variable(s) K, U exist so that Map<K, U> conforms to Function<U, V>" +
|
||||
"</body></html>"));
|
||||
assertTrue(tooltips.contains(
|
||||
"<html><body><table border=0><tr><td>" +
|
||||
"<b>identity( ) </b></td><td colspan=1>in <b>Function</b> cannot be applied</td></tr><tr><td>to</td><td><b>()</b> " +
|
||||
"</td></tr></table><br/>" +
|
||||
"reason: no instance(s) of type variable(s) K, U exist so that Map<K, U> conforms to Function<U, V>" +
|
||||
"</body></html>"));
|
||||
boolean found = false;
|
||||
for (String tooltip : tooltips) {
|
||||
if (tooltip.contains("reason: no instance(s) of type variable(s) K, U exist so that Map<K, U> conforms to Function<U, V>")) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
fail(StringUtil.join(tooltips, ", "));
|
||||
}
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
|
||||
+8
@@ -63,6 +63,14 @@ public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase {
|
||||
doTestCachedUnresolved();
|
||||
}
|
||||
|
||||
public void testCacheUnresolvedMethods4() throws Exception {
|
||||
doTestCachedUnresolved();
|
||||
}
|
||||
|
||||
public void testCacheUnresolvedMethods5() throws Exception {
|
||||
doTestCachedUnresolved();
|
||||
}
|
||||
|
||||
public void testMethodOverloadsInsideLambdaHierarchy() throws Exception {
|
||||
doTestAllMethodCallExpressions();
|
||||
}
|
||||
|
||||
+5
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,14 +27,17 @@ public class SurroundAutoCloseableActionTest extends LightCodeInsightFixtureTest
|
||||
}
|
||||
|
||||
public void testSimple() { doTest(); }
|
||||
public void testSimplePast() { doTest(); }
|
||||
public void testUsage() { doTest(); }
|
||||
public void testMixedUsages() { doTest(); }
|
||||
public void testLastDeclaration() { doTest(); }
|
||||
public void testSplitVar() { doTest(); }
|
||||
public void testExpression() { doTest(); }
|
||||
public void testExpressionIncomplete() { doTest(); }
|
||||
|
||||
private void doTest() {
|
||||
String name = getTestName(false);
|
||||
String intention = CodeInsightBundle.message("intention.surround.resource.with.ARM.block");
|
||||
CodeInsightTestUtil.doIntentionTest(myFixture, intention, name + ".java", name + "_after.java");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,19 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.navigation;
|
||||
|
||||
import com.intellij.application.options.editor.GutterIconsConfigurable;
|
||||
import com.intellij.codeInsight.daemon.GutterIconDescriptor;
|
||||
import com.intellij.codeInsight.daemon.GutterMark;
|
||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
||||
import com.intellij.testFramework.TestActionEvent;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Dmitry Avdeev
|
||||
@@ -68,4 +72,17 @@ public class RunLineMarkerTest extends LightCodeInsightFixtureTestCase {
|
||||
list.get(1).update(event);
|
||||
assertEquals("Run 'MainTest'", event.getPresentation().getText());
|
||||
}
|
||||
|
||||
public void testConfigurable() throws Exception {
|
||||
GutterIconsConfigurable configurable = new GutterIconsConfigurable();
|
||||
configurable.createComponent();
|
||||
List<GutterIconDescriptor> descriptors = configurable.getDescriptors();
|
||||
Set<String> strings = ContainerUtil.map2Set(descriptors, new Function<GutterIconDescriptor, String>() {
|
||||
@Override
|
||||
public String fun(GutterIconDescriptor descriptor) {
|
||||
return descriptor.getId();
|
||||
}
|
||||
});
|
||||
assertEquals(descriptors.size(), strings.size());
|
||||
}
|
||||
}
|
||||
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.template
|
||||
|
||||
import com.intellij.codeInsight.template.impl.InvokeTemplateAction
|
||||
import com.intellij.codeInsight.template.impl.SurroundWithTemplateHandler
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
|
||||
class SurroundWithTemplateTest extends LightCodeInsightFixtureTestCase {
|
||||
public void testSurroundWithTryWithResources() {
|
||||
myFixture.configureByText "C.java", """\
|
||||
import java.io.*;
|
||||
class C {
|
||||
void m() {
|
||||
new FileReader("/dev/null")<caret>
|
||||
}
|
||||
}""".stripIndent()
|
||||
|
||||
invokeTemplate("TR")
|
||||
|
||||
myFixture.checkResult """\
|
||||
import java.io.*;
|
||||
class C {
|
||||
void m() {
|
||||
try (FileReader fileReader = new FileReader("/dev/null")) {
|
||||
<caret>
|
||||
}
|
||||
|
||||
}
|
||||
}""".stripIndent()
|
||||
}
|
||||
|
||||
private void invokeTemplate(String template) {
|
||||
DefaultActionGroup group = SurroundWithTemplateHandler.createActionGroup(project, editor, file)
|
||||
assertNotNull(group)
|
||||
InvokeTemplateAction action = group.childActionsOrStubs.find {
|
||||
it instanceof InvokeTemplateAction && (it as InvokeTemplateAction).template.key == template
|
||||
} as InvokeTemplateAction
|
||||
assertNotNull(action)
|
||||
action.perform()
|
||||
}
|
||||
}
|
||||
@@ -675,6 +675,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
|
||||
doDuplicatesTest();
|
||||
}
|
||||
|
||||
public void testSuggestChangeSignatureWithOutputVariables() throws Exception {
|
||||
doDuplicatesTest();
|
||||
}
|
||||
|
||||
public void testSuggestChangeSignatureWithChangedParameterName() throws Exception {
|
||||
configureByFile(BASE_PATH + getTestName(false) + ".java");
|
||||
boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, null, false, "p");
|
||||
|
||||
@@ -68,6 +68,7 @@ public abstract class JspManager implements IBaseJspManager {
|
||||
|
||||
public abstract String[] getPossibleTldUris(@NotNull Module module);
|
||||
|
||||
@NotNull
|
||||
public abstract Collection<XmlFile> getPossibleTldFiles(@NotNull Module module);
|
||||
|
||||
@Nullable
|
||||
|
||||
+6
-4
@@ -25,6 +25,8 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.AtomicNotNullLazyValue;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.GlobalSearchScopes;
|
||||
import com.intellij.psi.search.GlobalSearchScopesCore;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiTypesUtil;
|
||||
@@ -218,7 +220,8 @@ public class GuavaInspection extends BaseJavaLocalInspectionTool {
|
||||
return false;
|
||||
}
|
||||
PsiClass aClass = method.getContainingClass();
|
||||
return aClass != null && GuavaFluentIterableConversionRule.FLUENT_ITERABLE.equals(aClass.getQualifiedName());
|
||||
return aClass != null && (GuavaOptionalConversionRule.GUAVA_OPTIONAL.equals(aClass.getQualifiedName()) ||
|
||||
GuavaFluentIterableConversionRule.FLUENT_ITERABLE.equals(aClass.getQualifiedName()));
|
||||
}
|
||||
|
||||
private PsiMethodCallExpression findGuavaMethodChain(PsiMethodCallExpression expression) {
|
||||
@@ -352,7 +355,6 @@ public class GuavaInspection extends BaseJavaLocalInspectionTool {
|
||||
|
||||
private static boolean performTypeMigration(List<PsiElement> elements, List<PsiType> types) {
|
||||
PsiFile containingFile = null;
|
||||
SearchScope typeMigrationScope = GlobalSearchScope.EMPTY_SCOPE;
|
||||
for (PsiElement element : elements) {
|
||||
final PsiFile currentContainingFile = element.getContainingFile();
|
||||
if (containingFile == null) {
|
||||
@@ -361,13 +363,13 @@ public class GuavaInspection extends BaseJavaLocalInspectionTool {
|
||||
else {
|
||||
LOG.assertTrue(containingFile.isEquivalentTo(currentContainingFile));
|
||||
}
|
||||
typeMigrationScope = typeMigrationScope.union(element.getUseScope());
|
||||
}
|
||||
LOG.assertTrue(containingFile != null);
|
||||
if (!FileModificationService.getInstance().prepareFileForWrite(containingFile)) return false;
|
||||
try {
|
||||
final TypeMigrationRules rules = new TypeMigrationRules();
|
||||
rules.setBoundScope(typeMigrationScope);
|
||||
rules.setBoundScope(GlobalSearchScopesCore.projectProductionScope(containingFile.getProject())
|
||||
.union(GlobalSearchScopesCore.projectTestScope(containingFile.getProject())));
|
||||
TypeMigrationProcessor.runHighlightingTypeMigration(containingFile.getProject(),
|
||||
null,
|
||||
rules,
|
||||
|
||||
+11
-2
@@ -98,8 +98,17 @@ public class GuavaConversionUtil {
|
||||
}
|
||||
else {
|
||||
final GuavaLambda lambda = GuavaLambda.findFor(evaluator.evaluateType(expression));
|
||||
return lambda == null ? expression
|
||||
: addMethodReference(expression, lambda);
|
||||
if (lambda == null) {
|
||||
return expression;
|
||||
}
|
||||
else {
|
||||
final PsiExpression expressionWithMethodReference = addMethodReference(expression, lambda);
|
||||
if (insertTypeCase) {
|
||||
return adjustLambdaContainingExpression(expressionWithMethodReference, true, targetType, evaluator);
|
||||
} else {
|
||||
return expressionWithMethodReference;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expression instanceof PsiMethodReferenceExpression) {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,5 @@
|
||||
asm-commons.jar
|
||||
asm.jar
|
||||
asm4-all.jar
|
||||
asm-all.jar
|
||||
automaton.jar
|
||||
cglib-2.2.2.jar
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,7 +26,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
class MockDocumentCommitProcessor extends DocumentCommitProcessor {
|
||||
class MockDocumentCommitProcessor implements DocumentCommitProcessor {
|
||||
@Override
|
||||
public void commitSynchronously(@NotNull Document document, @NotNull Project project, @NotNull PsiFile psiFile) {
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||
import com.intellij.util.concurrency.AppScheduledExecutorService;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -69,8 +70,8 @@ public class PerformanceWatcher implements ApplicationComponent {
|
||||
private volatile ApdexData myGeneralApdex = ApdexData.EMPTY;
|
||||
private volatile long myLastSampling = System.currentTimeMillis();
|
||||
private volatile long myLastAliveEdt = System.currentTimeMillis();
|
||||
private long myLastDumpTime = 0;
|
||||
private long myFreezeStart = 0;
|
||||
private long myLastDumpTime;
|
||||
private long myFreezeStart;
|
||||
|
||||
/**
|
||||
* If the product is unresponsive for UNRESPONSIVE_THRESHOLD_SECONDS, dump threads every UNRESPONSIVE_INTERVAL_SECONDS
|
||||
@@ -104,55 +105,36 @@ public class PerformanceWatcher implements ApplicationComponent {
|
||||
|
||||
@Override
|
||||
public void initComponent() {
|
||||
if (!shouldWatch()) return;
|
||||
UNRESPONSIVE_THRESHOLD_SECONDS = SystemProperties.getIntProperty("performance.watcher.threshold", 5);
|
||||
UNRESPONSIVE_INTERVAL_SECONDS = SystemProperties.getIntProperty("performance.watcher.interval", 5);
|
||||
|
||||
final AppScheduledExecutorService service = (AppScheduledExecutorService)AppExecutorUtil.getAppScheduledExecutorService();
|
||||
service.setNewThreadListener(new Consumer<Thread>() {
|
||||
private final int ourReasonableThreadPoolSize = Registry.intValue("core.pooled.threads");
|
||||
if (shouldWatch()) {
|
||||
final AppScheduledExecutorService service = (AppScheduledExecutorService)AppExecutorUtil.getAppScheduledExecutorService();
|
||||
service.setNewThreadListener(new Consumer<Thread>() {
|
||||
private final int ourReasonableThreadPoolSize = Registry.intValue("core.pooled.threads");
|
||||
|
||||
@Override
|
||||
public void consume(Thread thread) {
|
||||
if (service.getBackendPoolExecutorSize() > ourReasonableThreadPoolSize
|
||||
&& ApplicationInfoImpl.getShadowInstance().isEAP()) {
|
||||
File file = dumpThreads("newPooledThread/", true);
|
||||
LOG.info("Not enough pooled threads" + (file != null ? "; dumped threads into file '" + file.getPath() + "'" : ""));
|
||||
@Override
|
||||
public void consume(Thread thread) {
|
||||
if (service.getBackendPoolExecutorSize() > ourReasonableThreadPoolSize
|
||||
&& ApplicationInfoImpl.getShadowInstance().isEAP()) {
|
||||
File file = dumpThreads("newPooledThread/", true);
|
||||
LOG.info("Not enough pooled threads" + (file != null ? "; dumped threads into file '" + file.getPath() + "'" : ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
final String threshold = System.getProperty("performance.watcher.threshold");
|
||||
if (threshold != null) {
|
||||
try {
|
||||
UNRESPONSIVE_THRESHOLD_SECONDS = Integer.parseInt(threshold);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
final String interval = System.getProperty("performance.watcher.interval");
|
||||
if (interval != null) {
|
||||
try {
|
||||
UNRESPONSIVE_INTERVAL_SECONDS = Integer.parseInt(interval);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
if (UNRESPONSIVE_THRESHOLD_SECONDS == 0 || UNRESPONSIVE_INTERVAL_SECONDS == 0) {
|
||||
return;
|
||||
}
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
deleteOldThreadDumps();
|
||||
}
|
||||
});
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
deleteOldThreadDumps();
|
||||
}
|
||||
});
|
||||
|
||||
for (MemoryPoolMXBean bean : ManagementFactory.getMemoryPoolMXBeans()) {
|
||||
if ("Code Cache".equals(bean.getName())) {
|
||||
watchCodeCache(bean);
|
||||
return;
|
||||
for (MemoryPoolMXBean bean : ManagementFactory.getMemoryPoolMXBeans()) {
|
||||
if ("Code Cache".equals(bean.getName())) {
|
||||
watchCodeCache(bean);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,8 +188,7 @@ public class PerformanceWatcher implements ApplicationComponent {
|
||||
}
|
||||
|
||||
private boolean shouldWatch() {
|
||||
return !ApplicationManager.getApplication().isUnitTestMode() &&
|
||||
!ApplicationManager.getApplication().isHeadlessEnvironment() &&
|
||||
return !ApplicationManager.getApplication().isHeadlessEnvironment() &&
|
||||
UNRESPONSIVE_INTERVAL_SECONDS != 0 &&
|
||||
UNRESPONSIVE_THRESHOLD_SECONDS != 0;
|
||||
}
|
||||
|
||||
+4
-2
@@ -30,12 +30,14 @@ 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;
|
||||
|
||||
public class AbstractProgressIndicatorBase extends UserDataHolderBase implements ProgressIndicatorStacked {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.util.ProgressIndicatorBase");
|
||||
private static final CoreProgressManager ourProgressManager = (CoreProgressManager)ProgressManager.getInstance();
|
||||
@Nullable private final CoreProgressManager myProgressManager =
|
||||
ApplicationManager.getApplication() == null ? null : (CoreProgressManager)ProgressManager.getInstance();
|
||||
|
||||
private volatile String myText;
|
||||
private volatile double myFraction;
|
||||
@@ -128,7 +130,7 @@ public class AbstractProgressIndicatorBase extends UserDataHolderBase implements
|
||||
if (isCanceled() && isCancelable()) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
if (ourProgressManager.sleepIfNeeded()) {
|
||||
if (myProgressManager != null && myProgressManager.sleepIfNeeded()) {
|
||||
if (isCanceled() && isCancelable()) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ public class PomModelImpl extends UserDataHolderBase implements PomModel {
|
||||
|
||||
private void reparseFile(@NotNull final PsiFile file, @NotNull FileElement treeElement, @NotNull CharSequence newText) {
|
||||
PsiToDocumentSynchronizer synchronizer =((PsiDocumentManagerBase)PsiDocumentManager.getInstance(myProject)).getSynchronizer();
|
||||
TextRange changedPsiRange = DocumentCommitProcessor.getChangedPsiRange(file, treeElement, newText);
|
||||
TextRange changedPsiRange = DocumentCommitThread.getChangedPsiRange(file, treeElement, newText);
|
||||
if (changedPsiRange == null) return;
|
||||
|
||||
final DiffLog log = BlockSupport.getInstance(myProject).reparseRange(file, treeElement, changedPsiRange, newText, new EmptyProgressIndicator(),
|
||||
|
||||
@@ -15,300 +15,17 @@
|
||||
*/
|
||||
package com.intellij.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.FileASTNode;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Attachment;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.PomManager;
|
||||
import com.intellij.pom.PomModel;
|
||||
import com.intellij.pom.event.PomModelEvent;
|
||||
import com.intellij.pom.impl.PomTransactionBase;
|
||||
import com.intellij.pom.tree.TreeAspect;
|
||||
import com.intellij.pom.tree.TreeAspectEvent;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiLock;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.impl.source.PsiFileImpl;
|
||||
import com.intellij.psi.impl.source.text.DiffLog;
|
||||
import com.intellij.psi.impl.source.tree.FileElement;
|
||||
import com.intellij.psi.impl.source.tree.ForeignLeafPsiElement;
|
||||
import com.intellij.psi.impl.source.tree.TreeUtil;
|
||||
import com.intellij.psi.text.BlockSupport;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class DocumentCommitProcessor {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.DocumentCommitThread");
|
||||
|
||||
public abstract void commitSynchronously(@NotNull Document document, @NotNull Project project, @NotNull PsiFile psiFile);
|
||||
public abstract void commitAsynchronously(@NotNull final Project project,
|
||||
@NotNull final Document document,
|
||||
@NonNls @NotNull Object reason,
|
||||
@NotNull ModalityState currentModalityState);
|
||||
|
||||
protected static class CommitTask {
|
||||
static final Key<Object> CANCEL_REASON = Key.create("CANCEL_REASON");
|
||||
@NotNull final Document document;
|
||||
@NotNull final Project project;
|
||||
private final int modificationSequence; // store initial document modification sequence here to check if it changed later before commit in EDT
|
||||
|
||||
// when queued it's not started
|
||||
// when dequeued it's started
|
||||
// when failed it's canceled
|
||||
@NotNull final ProgressIndicator indicator; // progress to commit this doc under.
|
||||
@NotNull final Object reason;
|
||||
@NotNull final ModalityState myCreationModalityState;
|
||||
private final CharSequence myLastCommittedText;
|
||||
@NotNull final List<Pair<PsiFileImpl, FileASTNode>> myOldFileNodes;
|
||||
|
||||
protected CommitTask(@NotNull final Project project,
|
||||
@NotNull final Document document,
|
||||
@NotNull final List<Pair<PsiFileImpl, FileASTNode>> oldFileNodes,
|
||||
@NotNull ProgressIndicator indicator,
|
||||
@NotNull Object reason,
|
||||
@NotNull ModalityState currentModalityState) {
|
||||
this.document = document;
|
||||
this.project = project;
|
||||
this.indicator = indicator;
|
||||
this.reason = reason;
|
||||
myCreationModalityState = currentModalityState;
|
||||
myLastCommittedText = PsiDocumentManager.getInstance(project).getLastCommittedText(document);
|
||||
myOldFileNodes = oldFileNodes;
|
||||
modificationSequence = ((DocumentEx)document).getModificationSequence();
|
||||
}
|
||||
|
||||
@NonNls
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Doc: " + document + " (\"" + StringUtil.first(document.getImmutableCharSequence(), 40, true).toString().replaceAll("\n", " ") + "\")"
|
||||
+ (indicator.isCanceled() ? " (Canceled: " + ((UserDataHolder)indicator).getUserData(CANCEL_REASON) + ")":"")
|
||||
+" Reason: " + reason
|
||||
+ (isStillValid() ? "" : "; changed: old seq="+modificationSequence+", new seq="+ ((DocumentEx)document).getModificationSequence())
|
||||
;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof CommitTask)) return false;
|
||||
|
||||
CommitTask task = (CommitTask)o;
|
||||
|
||||
return document.equals(task.document) && project.equals(task.project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = document.hashCode();
|
||||
result = 31 * result + project.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isStillValid() {
|
||||
return ((DocumentEx)document).getModificationSequence() == modificationSequence;
|
||||
}
|
||||
|
||||
public void cancel(@NotNull Object reason, @NotNull DocumentCommitProcessor commitProcessor) {
|
||||
if (!indicator.isCanceled()) {
|
||||
commitProcessor.log(project, "indicator cancel", this);
|
||||
|
||||
indicator.cancel();
|
||||
((UserDataHolder)indicator).putUserData(CANCEL_REASON, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public for Upsource
|
||||
@Nullable("returns runnable to execute under write action in AWT to finish the commit")
|
||||
public Processor<Document> doCommit(@NotNull final CommitTask task,
|
||||
@NotNull final PsiFile file,
|
||||
@NotNull final FileASTNode oldFileNode) {
|
||||
Document document = task.document;
|
||||
final CharSequence newDocumentText = document.getImmutableCharSequence();
|
||||
final TextRange changedPsiRange = getChangedPsiRange(file, task.myLastCommittedText, newDocumentText);
|
||||
if (changedPsiRange == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Boolean data = document.getUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY);
|
||||
if (data != null) {
|
||||
document.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, null);
|
||||
file.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, data);
|
||||
}
|
||||
|
||||
BlockSupport blockSupport = BlockSupport.getInstance(file.getProject());
|
||||
final DiffLog diffLog = blockSupport.reparseRange(file, oldFileNode, changedPsiRange, newDocumentText, task.indicator, task.myLastCommittedText);
|
||||
|
||||
return new Processor<Document>() {
|
||||
@Override
|
||||
public boolean process(Document document) {
|
||||
ApplicationManager.getApplication().assertWriteAccessAllowed();
|
||||
if (!task.isStillValid() ||
|
||||
((PsiDocumentManagerBase)PsiDocumentManager.getInstance(file.getProject())).getCachedViewProvider(document) != file.getViewProvider()) {
|
||||
return false; // optimistic locking failed
|
||||
}
|
||||
|
||||
doActualPsiChange(file, diffLog);
|
||||
|
||||
assertAfterCommit(document, file, (FileElement)oldFileNode);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static int getLeafMatchingLength(CharSequence leafText, CharSequence pattern, int patternIndex, int finalPatternIndex, int direction) {
|
||||
int leafIndex = direction == 1 ? 0 : leafText.length() - 1;
|
||||
int finalLeafIndex = direction == 1 ? leafText.length() - 1 : 0;
|
||||
int result = 0;
|
||||
while (leafText.charAt(leafIndex) == pattern.charAt(patternIndex)) {
|
||||
result++;
|
||||
if (leafIndex == finalLeafIndex || patternIndex == finalPatternIndex) {
|
||||
break;
|
||||
}
|
||||
leafIndex += direction;
|
||||
patternIndex += direction;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int getMatchingLength(@NotNull FileElement treeElement, @NotNull CharSequence text, boolean fromStart) {
|
||||
int patternIndex = fromStart ? 0 : text.length() - 1;
|
||||
int finalPatternIndex = fromStart ? text.length() - 1 : 0;
|
||||
int direction = fromStart ? 1 : -1;
|
||||
ASTNode leaf = fromStart ? TreeUtil.findFirstLeaf(treeElement, false) : TreeUtil.findLastLeaf(treeElement, false);
|
||||
int result = 0;
|
||||
while (leaf != null && (fromStart ? patternIndex <= finalPatternIndex : patternIndex >= finalPatternIndex)) {
|
||||
if (!(leaf instanceof ForeignLeafPsiElement)) {
|
||||
CharSequence chars = leaf.getChars();
|
||||
if (chars.length() > 0) {
|
||||
int matchingLength = getLeafMatchingLength(chars, text, patternIndex, finalPatternIndex, direction);
|
||||
result += matchingLength;
|
||||
if (matchingLength != chars.length()) {
|
||||
break;
|
||||
}
|
||||
patternIndex += fromStart ? matchingLength : -matchingLength;
|
||||
}
|
||||
}
|
||||
leaf = fromStart ? TreeUtil.nextLeaf(leaf, false) : TreeUtil.prevLeaf(leaf, false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TextRange getChangedPsiRange(@NotNull PsiFile file, @NotNull FileElement treeElement, @NotNull CharSequence newDocumentText) {
|
||||
int psiLength = treeElement.getTextLength();
|
||||
if (!file.getViewProvider().supportsIncrementalReparse(file.getLanguage())) {
|
||||
return new TextRange(0, psiLength);
|
||||
}
|
||||
|
||||
int commonPrefixLength = getMatchingLength(treeElement, newDocumentText, true);
|
||||
if (commonPrefixLength == newDocumentText.length() && newDocumentText.length() == psiLength) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int commonSuffixLength = Math.min(getMatchingLength(treeElement, newDocumentText, false), psiLength - commonPrefixLength);
|
||||
return new TextRange(commonPrefixLength, psiLength - commonSuffixLength);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TextRange getChangedPsiRange(@NotNull PsiFile file,
|
||||
@NotNull CharSequence oldDocumentText,
|
||||
@NotNull CharSequence newDocumentText) {
|
||||
int psiLength = oldDocumentText.length();
|
||||
if (!file.getViewProvider().supportsIncrementalReparse(file.getLanguage())) {
|
||||
return new TextRange(0, psiLength);
|
||||
}
|
||||
|
||||
int commonPrefixLength = StringUtil.commonPrefixLength(oldDocumentText, newDocumentText);
|
||||
if (commonPrefixLength == newDocumentText.length() && newDocumentText.length() == psiLength) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int commonSuffixLength = Math.min(StringUtil.commonSuffixLength(oldDocumentText, newDocumentText), psiLength - commonPrefixLength);
|
||||
return new TextRange(commonPrefixLength, psiLength - commonSuffixLength);
|
||||
}
|
||||
|
||||
public static void doActualPsiChange(@NotNull final PsiFile file, @NotNull final DiffLog diffLog) {
|
||||
CodeStyleManager.getInstance(file.getProject()).performActionWithFormatterDisabled(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (PsiLock.LOCK) {
|
||||
file.getViewProvider().beforeContentsSynchronized();
|
||||
|
||||
final Document document = file.getViewProvider().getDocument();
|
||||
PsiDocumentManagerBase documentManager = (PsiDocumentManagerBase)PsiDocumentManager.getInstance(file.getProject());
|
||||
PsiToDocumentSynchronizer.DocumentChangeTransaction transaction = documentManager.getSynchronizer().getTransaction(document);
|
||||
|
||||
final PsiFileImpl fileImpl = (PsiFileImpl)file;
|
||||
|
||||
if (transaction == null) {
|
||||
final PomModel model = PomManager.getModel(fileImpl.getProject());
|
||||
|
||||
model.runTransaction(new PomTransactionBase(fileImpl, model.getModelAspect(TreeAspect.class)) {
|
||||
@Override
|
||||
public PomModelEvent runInner() {
|
||||
return new TreeAspectEvent(model, diffLog.performActualPsiChange(file));
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
diffLog.performActualPsiChange(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void assertAfterCommit(@NotNull Document document,
|
||||
@NotNull final PsiFile file,
|
||||
@NotNull FileElement oldFileNode) {
|
||||
if (oldFileNode.getTextLength() != document.getTextLength()) {
|
||||
final String documentText = document.getText();
|
||||
String fileText = file.getText();
|
||||
boolean sameText = Comparing.equal(fileText, documentText);
|
||||
LOG.error("commitDocument() left PSI inconsistent: " + DebugUtil.diagnosePsiDocumentInconsistency(file, document) +
|
||||
"; node.length=" + oldFileNode.getTextLength() +
|
||||
"; doc.text" + (sameText ? "==" : "!=") + "file.text",
|
||||
new Attachment("file psi text", fileText),
|
||||
new Attachment("old text", documentText));
|
||||
|
||||
file.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE);
|
||||
try {
|
||||
BlockSupport blockSupport = BlockSupport.getInstance(file.getProject());
|
||||
final DiffLog diffLog = blockSupport.reparseRange(file, file.getNode(), new TextRange(0, documentText.length()), documentText, createProgressIndicator(),
|
||||
oldFileNode.getText());
|
||||
doActualPsiChange(file, diffLog);
|
||||
|
||||
if (oldFileNode.getTextLength() != document.getTextLength()) {
|
||||
LOG.error("PSI is broken beyond repair in: " + file);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
file.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void log(Project project, @NonNls String msg, @Nullable CommitTask task, @NonNls Object... args) {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected ProgressIndicator createProgressIndicator() {
|
||||
return new EmptyProgressIndicator();
|
||||
}
|
||||
public interface DocumentCommitProcessor {
|
||||
void commitSynchronously(@NotNull Document document, @NotNull Project project, @NotNull PsiFile psiFile);
|
||||
void commitAsynchronously(@NotNull final Project project,
|
||||
@NotNull final Document document,
|
||||
@NonNls @NotNull Object reason,
|
||||
@NotNull ModalityState currentModalityState);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.psi.impl;
|
||||
|
||||
import com.intellij.diagnostic.ThreadDumper;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.FileASTNode;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationAdapter;
|
||||
@@ -23,8 +24,10 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.ex.ApplicationEx;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Attachment;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
@@ -32,10 +35,23 @@ import com.intellij.openapi.progress.util.StandardProgressIndicatorBase;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.PomManager;
|
||||
import com.intellij.pom.PomModel;
|
||||
import com.intellij.pom.event.PomModelEvent;
|
||||
import com.intellij.pom.impl.PomTransactionBase;
|
||||
import com.intellij.pom.tree.TreeAspect;
|
||||
import com.intellij.pom.tree.TreeAspectEvent;
|
||||
import com.intellij.psi.FileViewProvider;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiLock;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.impl.source.PsiFileImpl;
|
||||
import com.intellij.psi.impl.source.text.DiffLog;
|
||||
import com.intellij.psi.impl.source.tree.FileElement;
|
||||
import com.intellij.psi.impl.source.tree.ForeignLeafPsiElement;
|
||||
import com.intellij.psi.impl.source.tree.TreeUtil;
|
||||
import com.intellij.psi.text.BlockSupport;
|
||||
import com.intellij.util.ExceptionUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.Processor;
|
||||
@@ -60,7 +76,7 @@ import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class DocumentCommitThread extends DocumentCommitProcessor implements Runnable, Disposable {
|
||||
public class DocumentCommitThread implements Runnable, Disposable, DocumentCommitProcessor {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.DocumentCommitThread");
|
||||
|
||||
private final ExecutorService executor = new BoundedTaskExecutor(PooledThreadExecutor.INSTANCE, 1, this);
|
||||
@@ -74,7 +90,7 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run
|
||||
private int runningWriteActions; // accessed in EDT only
|
||||
|
||||
public static DocumentCommitThread getInstance() {
|
||||
return ServiceManager.getService(DocumentCommitThread.class);
|
||||
return (DocumentCommitThread)ServiceManager.getService(DocumentCommitProcessor.class);
|
||||
}
|
||||
public DocumentCommitThread(final ApplicationEx application) {
|
||||
myApplication = application;
|
||||
@@ -158,13 +174,6 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run
|
||||
@NotNull final Document document,
|
||||
@NonNls @NotNull Object reason,
|
||||
@NotNull ModalityState currentModalityState) {
|
||||
queueCommit(project, document, reason, currentModalityState);
|
||||
}
|
||||
|
||||
void queueCommit(@NotNull final Project project,
|
||||
@NotNull final Document document,
|
||||
@NonNls @NotNull Object reason,
|
||||
@NotNull ModalityState currentModalityState) {
|
||||
assert !isDisposed : "already disposed";
|
||||
|
||||
if (!project.isInitialized()) return;
|
||||
@@ -213,7 +222,6 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run
|
||||
final StringBuilder log = new StringBuilder();
|
||||
|
||||
@SuppressWarnings({"NonConstantStringShouldBeStringBuffer", "StringConcatenationInLoop"})
|
||||
@Override
|
||||
public void log(Project project, @NonNls String msg, @Nullable CommitTask task, @NonNls Object... args) {
|
||||
if (true) return;
|
||||
|
||||
@@ -486,7 +494,6 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected ProgressIndicator createProgressIndicator() {
|
||||
return new StandardProgressIndicatorBase();
|
||||
}
|
||||
@@ -589,7 +596,7 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run
|
||||
}
|
||||
else {
|
||||
// add document back to the queue
|
||||
queueCommit(project, document, "Re-added back", task.myCreationModalityState);
|
||||
commitAsynchronously(project, document, "Re-added back", task.myCreationModalityState);
|
||||
}
|
||||
}
|
||||
catch (Error e) {
|
||||
@@ -637,4 +644,247 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run
|
||||
((BoundedTaskExecutor)executor).waitAllTasksExecuted(100, TimeUnit.SECONDS);
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
}
|
||||
|
||||
|
||||
private static class CommitTask {
|
||||
static final Key<Object> CANCEL_REASON = Key.create("CANCEL_REASON");
|
||||
@NotNull final Document document;
|
||||
@NotNull final Project project;
|
||||
private final int modificationSequence; // store initial document modification sequence here to check if it changed later before commit in EDT
|
||||
|
||||
// when queued it's not started
|
||||
// when dequeued it's started
|
||||
// when failed it's canceled
|
||||
@NotNull final ProgressIndicator indicator; // progress to commit this doc under.
|
||||
@NotNull final Object reason;
|
||||
@NotNull final ModalityState myCreationModalityState;
|
||||
private final CharSequence myLastCommittedText;
|
||||
@NotNull final List<Pair<PsiFileImpl, FileASTNode>> myOldFileNodes;
|
||||
|
||||
protected CommitTask(@NotNull final Project project,
|
||||
@NotNull final Document document,
|
||||
@NotNull final List<Pair<PsiFileImpl, FileASTNode>> oldFileNodes,
|
||||
@NotNull ProgressIndicator indicator,
|
||||
@NotNull Object reason,
|
||||
@NotNull ModalityState currentModalityState) {
|
||||
this.document = document;
|
||||
this.project = project;
|
||||
this.indicator = indicator;
|
||||
this.reason = reason;
|
||||
myCreationModalityState = currentModalityState;
|
||||
myLastCommittedText = PsiDocumentManager.getInstance(project).getLastCommittedText(document);
|
||||
myOldFileNodes = oldFileNodes;
|
||||
modificationSequence = ((DocumentEx)document).getModificationSequence();
|
||||
}
|
||||
|
||||
@NonNls
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Doc: " + document + " (\"" + StringUtil.first(document.getImmutableCharSequence(), 40, true).toString().replaceAll("\n", " ") + "\")"
|
||||
+ (indicator.isCanceled() ? " (Canceled: " + ((UserDataHolder)indicator).getUserData(CANCEL_REASON) + ")":"")
|
||||
+" Reason: " + reason
|
||||
+ (isStillValid() ? "" : "; changed: old seq="+modificationSequence+", new seq="+ ((DocumentEx)document).getModificationSequence())
|
||||
;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof CommitTask)) return false;
|
||||
|
||||
CommitTask task = (CommitTask)o;
|
||||
|
||||
return document.equals(task.document) && project.equals(task.project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = document.hashCode();
|
||||
result = 31 * result + project.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isStillValid() {
|
||||
return ((DocumentEx)document).getModificationSequence() == modificationSequence;
|
||||
}
|
||||
|
||||
private void cancel(@NotNull Object reason, @NotNull DocumentCommitThread commitProcessor) {
|
||||
if (!indicator.isCanceled()) {
|
||||
commitProcessor.log(project, "indicator cancel", this);
|
||||
|
||||
indicator.cancel();
|
||||
((UserDataHolder)indicator).putUserData(CANCEL_REASON, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public for Upsource
|
||||
@Nullable("returns runnable to execute under write action in AWT to finish the commit")
|
||||
public Processor<Document> doCommit(@NotNull final CommitTask task,
|
||||
@NotNull final PsiFile file,
|
||||
@NotNull final FileASTNode oldFileNode) {
|
||||
Document document = task.document;
|
||||
final CharSequence newDocumentText = document.getImmutableCharSequence();
|
||||
final TextRange changedPsiRange = getChangedPsiRange(file, task.myLastCommittedText, newDocumentText);
|
||||
if (changedPsiRange == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Boolean data = document.getUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY);
|
||||
if (data != null) {
|
||||
document.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, null);
|
||||
file.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, data);
|
||||
}
|
||||
|
||||
BlockSupport blockSupport = BlockSupport.getInstance(file.getProject());
|
||||
final DiffLog diffLog = blockSupport.reparseRange(file, oldFileNode, changedPsiRange, newDocumentText, task.indicator, task.myLastCommittedText);
|
||||
|
||||
return new Processor<Document>() {
|
||||
@Override
|
||||
public boolean process(Document document) {
|
||||
ApplicationManager.getApplication().assertWriteAccessAllowed();
|
||||
if (!task.isStillValid() ||
|
||||
((PsiDocumentManagerBase)PsiDocumentManager.getInstance(file.getProject())).getCachedViewProvider(document) != file.getViewProvider()) {
|
||||
return false; // optimistic locking failed
|
||||
}
|
||||
|
||||
doActualPsiChange(file, diffLog);
|
||||
|
||||
assertAfterCommit(document, file, (FileElement)oldFileNode);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static int getLeafMatchingLength(CharSequence leafText, CharSequence pattern, int patternIndex, int finalPatternIndex, int direction) {
|
||||
int leafIndex = direction == 1 ? 0 : leafText.length() - 1;
|
||||
int finalLeafIndex = direction == 1 ? leafText.length() - 1 : 0;
|
||||
int result = 0;
|
||||
while (leafText.charAt(leafIndex) == pattern.charAt(patternIndex)) {
|
||||
result++;
|
||||
if (leafIndex == finalLeafIndex || patternIndex == finalPatternIndex) {
|
||||
break;
|
||||
}
|
||||
leafIndex += direction;
|
||||
patternIndex += direction;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int getMatchingLength(@NotNull FileElement treeElement, @NotNull CharSequence text, boolean fromStart) {
|
||||
int patternIndex = fromStart ? 0 : text.length() - 1;
|
||||
int finalPatternIndex = fromStart ? text.length() - 1 : 0;
|
||||
int direction = fromStart ? 1 : -1;
|
||||
ASTNode leaf = fromStart ? TreeUtil.findFirstLeaf(treeElement, false) : TreeUtil.findLastLeaf(treeElement, false);
|
||||
int result = 0;
|
||||
while (leaf != null && (fromStart ? patternIndex <= finalPatternIndex : patternIndex >= finalPatternIndex)) {
|
||||
if (!(leaf instanceof ForeignLeafPsiElement)) {
|
||||
CharSequence chars = leaf.getChars();
|
||||
if (chars.length() > 0) {
|
||||
int matchingLength = getLeafMatchingLength(chars, text, patternIndex, finalPatternIndex, direction);
|
||||
result += matchingLength;
|
||||
if (matchingLength != chars.length()) {
|
||||
break;
|
||||
}
|
||||
patternIndex += fromStart ? matchingLength : -matchingLength;
|
||||
}
|
||||
}
|
||||
leaf = fromStart ? TreeUtil.nextLeaf(leaf, false) : TreeUtil.prevLeaf(leaf, false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TextRange getChangedPsiRange(@NotNull PsiFile file, @NotNull FileElement treeElement, @NotNull CharSequence newDocumentText) {
|
||||
int psiLength = treeElement.getTextLength();
|
||||
if (!file.getViewProvider().supportsIncrementalReparse(file.getLanguage())) {
|
||||
return new TextRange(0, psiLength);
|
||||
}
|
||||
|
||||
int commonPrefixLength = getMatchingLength(treeElement, newDocumentText, true);
|
||||
if (commonPrefixLength == newDocumentText.length() && newDocumentText.length() == psiLength) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int commonSuffixLength = Math.min(getMatchingLength(treeElement, newDocumentText, false), psiLength - commonPrefixLength);
|
||||
return new TextRange(commonPrefixLength, psiLength - commonSuffixLength);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TextRange getChangedPsiRange(@NotNull PsiFile file,
|
||||
@NotNull CharSequence oldDocumentText,
|
||||
@NotNull CharSequence newDocumentText) {
|
||||
int psiLength = oldDocumentText.length();
|
||||
if (!file.getViewProvider().supportsIncrementalReparse(file.getLanguage())) {
|
||||
return new TextRange(0, psiLength);
|
||||
}
|
||||
|
||||
int commonPrefixLength = StringUtil.commonPrefixLength(oldDocumentText, newDocumentText);
|
||||
if (commonPrefixLength == newDocumentText.length() && newDocumentText.length() == psiLength) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int commonSuffixLength = Math.min(StringUtil.commonSuffixLength(oldDocumentText, newDocumentText), psiLength - commonPrefixLength);
|
||||
return new TextRange(commonPrefixLength, psiLength - commonSuffixLength);
|
||||
}
|
||||
|
||||
public static void doActualPsiChange(@NotNull final PsiFile file, @NotNull final DiffLog diffLog) {
|
||||
CodeStyleManager.getInstance(file.getProject()).performActionWithFormatterDisabled(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (PsiLock.LOCK) {
|
||||
file.getViewProvider().beforeContentsSynchronized();
|
||||
|
||||
final Document document = file.getViewProvider().getDocument();
|
||||
PsiDocumentManagerBase documentManager = (PsiDocumentManagerBase)PsiDocumentManager.getInstance(file.getProject());
|
||||
PsiToDocumentSynchronizer.DocumentChangeTransaction transaction = documentManager.getSynchronizer().getTransaction(document);
|
||||
|
||||
final PsiFileImpl fileImpl = (PsiFileImpl)file;
|
||||
|
||||
if (transaction == null) {
|
||||
final PomModel model = PomManager.getModel(fileImpl.getProject());
|
||||
|
||||
model.runTransaction(new PomTransactionBase(fileImpl, model.getModelAspect(TreeAspect.class)) {
|
||||
@Override
|
||||
public PomModelEvent runInner() {
|
||||
return new TreeAspectEvent(model, diffLog.performActualPsiChange(file));
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
diffLog.performActualPsiChange(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void assertAfterCommit(@NotNull Document document, @NotNull final PsiFile file, @NotNull FileElement oldFileNode) {
|
||||
if (oldFileNode.getTextLength() != document.getTextLength()) {
|
||||
final String documentText = document.getText();
|
||||
String fileText = file.getText();
|
||||
boolean sameText = Comparing.equal(fileText, documentText);
|
||||
LOG.error("commitDocument() left PSI inconsistent: " + DebugUtil.diagnosePsiDocumentInconsistency(file, document) +
|
||||
"; node.length=" + oldFileNode.getTextLength() +
|
||||
"; doc.text" + (sameText ? "==" : "!=") + "file.text",
|
||||
new Attachment("file psi text", fileText),
|
||||
new Attachment("old text", documentText));
|
||||
|
||||
file.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE);
|
||||
try {
|
||||
BlockSupport blockSupport = BlockSupport.getInstance(file.getProject());
|
||||
final DiffLog diffLog = blockSupport.reparseRange(file, file.getNode(), new TextRange(0, documentText.length()), documentText, createProgressIndicator(),
|
||||
oldFileNode.getText());
|
||||
doActualPsiChange(file, diffLog);
|
||||
|
||||
if (oldFileNode.getTextLength() != document.getTextLength()) {
|
||||
LOG.error("PSI is broken beyond repair in: " + file);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
file.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class SyntheticFileSystemItem extends PsiElementBase implements PsiFileSystemItem {
|
||||
public static final Logger LOG = Logger.getInstance("#" + SyntheticFileSystemItem.class.getPackage().getName());
|
||||
private static final Logger LOG = Logger.getInstance("#" + SyntheticFileSystemItem.class.getPackage().getName());
|
||||
|
||||
protected final Project myProject;
|
||||
protected final PsiManager myManager;
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.CheckinProjectPanel;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsConfiguration;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -49,7 +50,7 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp
|
||||
|
||||
protected final JPanel myPanel;
|
||||
protected final JCheckBox myAmend;
|
||||
@Nullable private String myPreviousMessage;
|
||||
@Nullable private final String myPreviousMessage;
|
||||
@Nullable private String myAmendedMessage;
|
||||
@NotNull protected final CheckinProjectPanel myCheckinPanel;
|
||||
@Nullable private Map<VirtualFile, String> myMessagesForRoots;
|
||||
@@ -140,8 +141,8 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp
|
||||
}
|
||||
|
||||
private void substituteCommitMessage(@NotNull String newMessage) {
|
||||
myPreviousMessage = myCheckinPanel.getCommitMessage();
|
||||
if (!myPreviousMessage.trim().equals(newMessage.trim())) {
|
||||
VcsConfiguration.getInstance(myCheckinPanel.getProject()).saveCommitMessage(myPreviousMessage);
|
||||
myCheckinPanel.setCommitMessage(newMessage);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -606,7 +606,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme {
|
||||
Element element = new Element(OPTION_ELEMENT);
|
||||
element.setAttribute(NAME_ATTR, key.getExternalName());
|
||||
if (baseKey != null && value.isFallbackEnabled()) {
|
||||
if (defaultFallbackAttr != null && defaultAttr != null && defaultAttr != defaultFallbackAttr) {
|
||||
if (isParentOverwritingInheritance(key)) {
|
||||
element.setAttribute(BASE_ATTRIBUTES_ATTR, baseKey.getExternalName());
|
||||
attrElements.addContent(element);
|
||||
}
|
||||
@@ -622,6 +622,15 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isParentOverwritingInheritance(@NotNull TextAttributesKey key) {
|
||||
TextAttributes parentAttrs =
|
||||
myParentScheme instanceof AbstractColorsScheme ? ((AbstractColorsScheme)myParentScheme).getDirectlyDefinedAttributes(key) : null;
|
||||
if (parentAttrs != null) {
|
||||
return !parentAttrs.isFallbackEnabled();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Color getOwnColor(ColorKey key) {
|
||||
return myColorsMap.get(key);
|
||||
}
|
||||
|
||||
@@ -73,6 +73,10 @@ public abstract class GutterIconDescriptor {
|
||||
myIcon = icon;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return LineMarkerSettings.getSettings().isEnabled(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.intellij.openapi.vfs.ex.http.HttpFileSystem;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import gnu.trove.TIntArrayList;
|
||||
@@ -107,6 +108,12 @@ public class PathEditor {
|
||||
public JComponent createComponent() {
|
||||
myList = new JBList(getListModel());
|
||||
myList.setCellRenderer(createListCellRenderer(myList));
|
||||
TreeUIHelper.getInstance().installListSpeedSearch(myList, new Convertor<Object, String>() {
|
||||
@Override
|
||||
public String convert(Object file) {
|
||||
return ((VirtualFile)file).getPresentableUrl();
|
||||
}
|
||||
});
|
||||
|
||||
ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myList)
|
||||
.disableUpDownActions()
|
||||
|
||||
+14
-2
@@ -32,10 +32,12 @@ import com.intellij.util.Function;
|
||||
import com.intellij.util.NullableFunction;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.containers.hash.HashSet;
|
||||
import com.intellij.util.ui.EmptyIcon;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -80,6 +82,7 @@ public class GutterIconsConfigurable implements Configurable, Configurable.NoScr
|
||||
};
|
||||
MultiMap<PluginDescriptor, LanguageExtensionPoint<LineMarkerProvider>> map = ContainerUtil.groupBy(Arrays.asList(extensions), function);
|
||||
Map<GutterIconDescriptor, PluginDescriptor> pluginDescriptorMap = ContainerUtil.newHashMap();
|
||||
Set<String> ids = new HashSet<>();
|
||||
myDescriptors = new ArrayList<GutterIconDescriptor>();
|
||||
for (final PluginDescriptor descriptor : map.keySet()) {
|
||||
Collection<LanguageExtensionPoint<LineMarkerProvider>> points = map.get(descriptor);
|
||||
@@ -87,16 +90,21 @@ public class GutterIconsConfigurable implements Configurable, Configurable.NoScr
|
||||
GutterIconDescriptor instance = (GutterIconDescriptor)extensionPoint.getInstance();
|
||||
if (instance.getOptions().length > 0) {
|
||||
for (GutterIconDescriptor option : instance.getOptions()) {
|
||||
myDescriptors.add(option);
|
||||
if (ids.add(option.getId())) {
|
||||
myDescriptors.add(option);
|
||||
}
|
||||
pluginDescriptorMap.put(option, descriptor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
myDescriptors.add(instance);
|
||||
if (ids.add(instance.getId())) {
|
||||
myDescriptors.add(instance);
|
||||
}
|
||||
pluginDescriptorMap.put(instance, descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
List<GutterIconDescriptor> options = new ArrayList<GutterIconDescriptor>();
|
||||
for (Iterator<GutterIconDescriptor> iterator = myDescriptors.iterator(); iterator.hasNext(); ) {
|
||||
GutterIconDescriptor descriptor = iterator.next();
|
||||
@@ -106,6 +114,7 @@ public class GutterIconsConfigurable implements Configurable, Configurable.NoScr
|
||||
}
|
||||
}
|
||||
myDescriptors.addAll(options);
|
||||
*/
|
||||
myDescriptors.sort(new Comparator<GutterIconDescriptor>() {
|
||||
@Override
|
||||
public int compare(GutterIconDescriptor o1, GutterIconDescriptor o2) {
|
||||
@@ -203,4 +212,7 @@ public class GutterIconsConfigurable implements Configurable, Configurable.NoScr
|
||||
};
|
||||
myList.setBorder(BorderFactory.createEmptyBorder());
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public List<GutterIconDescriptor> getDescriptors() { return myDescriptors; }
|
||||
}
|
||||
|
||||
+35
-61
@@ -60,6 +60,7 @@ import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.ReferenceRange;
|
||||
import com.intellij.ui.GuiUtils;
|
||||
import com.intellij.ui.LightweightHint;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
@@ -76,7 +77,6 @@ import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -129,7 +129,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
|
||||
private volatile boolean myHasPsiElements;
|
||||
private boolean myLookupUpdated;
|
||||
private final ConcurrentMap<LookupElement, CompletionSorterImpl> myItemSorters =
|
||||
ContainerUtil.createConcurrentWeakMap(ContainerUtil.<LookupElement>identityStrategy());
|
||||
ContainerUtil.createConcurrentWeakMap(ContainerUtil.identityStrategy());
|
||||
private final PropertyChangeListener myLookupManagerListener;
|
||||
private final Queue<Runnable> myAdvertiserChanges = new ConcurrentLinkedQueue<Runnable>();
|
||||
private final List<CompletionResult> myDelayedMiddleMatches = ContainerUtil.newArrayList();
|
||||
@@ -152,24 +152,16 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
|
||||
myLookup = lookup;
|
||||
myStartCaret = myEditor.getCaretModel().getOffset();
|
||||
|
||||
myAdvertiserChanges.offer(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myLookup.getAdvertiser().clearAdvertisements();
|
||||
}
|
||||
});
|
||||
myAdvertiserChanges.offer(() -> myLookup.getAdvertiser().clearAdvertisements());
|
||||
|
||||
myLookup.setArranger(new CompletionLookupArranger(parameters, this));
|
||||
|
||||
myLookup.addLookupListener(myLookupListener);
|
||||
myLookup.setCalculating(true);
|
||||
|
||||
myLookupManagerListener = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (evt.getNewValue() != null) {
|
||||
LOG.error("An attempt to change the lookup during completion, phase = " + CompletionServiceImpl.getCompletionPhase());
|
||||
}
|
||||
myLookupManagerListener = evt -> {
|
||||
if (evt.getNewValue() != null) {
|
||||
LOG.error("An attempt to change the lookup during completion, phase = " + CompletionServiceImpl.getCompletionPhase());
|
||||
}
|
||||
};
|
||||
LookupManager.getInstance(getProject()).addPropertyChangeListener(myLookupManagerListener);
|
||||
@@ -508,43 +500,40 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
|
||||
myQueue.cancelAllUpdates();
|
||||
myFreezeSemaphore.up();
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final CompletionPhase phase = CompletionServiceImpl.getCompletionPhase();
|
||||
if (!(phase instanceof CompletionPhase.BgCalculation) || phase.indicator != CompletionProgressIndicator.this) return;
|
||||
GuiUtils.invokeLaterIfNeeded(() -> {
|
||||
final CompletionPhase phase = CompletionServiceImpl.getCompletionPhase();
|
||||
if (!(phase instanceof CompletionPhase.BgCalculation) || phase.indicator != this) return;
|
||||
|
||||
LOG.assertTrue(!getProject().isDisposed(), "project disposed");
|
||||
LOG.assertTrue(!getProject().isDisposed(), "project disposed");
|
||||
|
||||
if (myEditor.isDisposed()) {
|
||||
myLookup.hideLookup(false);
|
||||
CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion);
|
||||
return;
|
||||
}
|
||||
if (myEditor.isDisposed()) {
|
||||
myLookup.hideLookup(false);
|
||||
CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion);
|
||||
return;
|
||||
}
|
||||
|
||||
if (myEditor instanceof EditorWindow) {
|
||||
LOG.assertTrue(((EditorWindow)myEditor).getInjectedFile().isValid(), "injected file !valid");
|
||||
LOG.assertTrue(((DocumentWindow)myEditor.getDocument()).isValid(), "docWindow !valid");
|
||||
}
|
||||
PsiFile file = myLookup.getPsiFile();
|
||||
LOG.assertTrue(file == null || file.isValid(), "file !valid");
|
||||
if (myEditor instanceof EditorWindow) {
|
||||
LOG.assertTrue(((EditorWindow)myEditor).getInjectedFile().isValid(), "injected file !valid");
|
||||
LOG.assertTrue(((DocumentWindow)myEditor.getDocument()).isValid(), "docWindow !valid");
|
||||
}
|
||||
PsiFile file = myLookup.getPsiFile();
|
||||
LOG.assertTrue(file == null || file.isValid(), "file !valid");
|
||||
|
||||
myLookup.setCalculating(false);
|
||||
myLookup.setCalculating(false);
|
||||
|
||||
if (myCount == 0) {
|
||||
myLookup.hideLookup(false);
|
||||
if (!isAutopopupCompletion()) {
|
||||
final CompletionProgressIndicator current = CompletionServiceImpl.getCompletionService().getCurrentCompletion();
|
||||
LOG.assertTrue(current == null, current + "!=" + CompletionProgressIndicator.this);
|
||||
if (myCount == 0) {
|
||||
myLookup.hideLookup(false);
|
||||
if (!isAutopopupCompletion()) {
|
||||
final CompletionProgressIndicator current = CompletionServiceImpl.getCompletionService().getCurrentCompletion();
|
||||
LOG.assertTrue(current == null, current + "!=" + this);
|
||||
|
||||
handleEmptyLookup(!((CompletionPhase.BgCalculation)phase).modifiersChanged);
|
||||
}
|
||||
}
|
||||
else {
|
||||
CompletionServiceImpl.setCompletionPhase(new CompletionPhase.ItemsCalculated(CompletionProgressIndicator.this));
|
||||
updateLookup();
|
||||
handleEmptyLookup(!((CompletionPhase.BgCalculation)phase).modifiersChanged);
|
||||
}
|
||||
}
|
||||
else {
|
||||
CompletionServiceImpl.setCompletionPhase(new CompletionPhase.ItemsCalculated(this));
|
||||
updateLookup();
|
||||
}
|
||||
}, myQueue.getModalityState());
|
||||
}
|
||||
|
||||
@@ -740,12 +729,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
|
||||
|
||||
private static LightweightHint showErrorHint(Project project, Editor editor, String text) {
|
||||
final LightweightHint[] result = {null};
|
||||
final EditorHintListener listener = new EditorHintListener() {
|
||||
@Override
|
||||
public void hintShown(final Project project, final LightweightHint hint, final int flags) {
|
||||
result[0] = hint;
|
||||
}
|
||||
};
|
||||
final EditorHintListener listener = (project1, hint, flags) -> result[0] = hint;
|
||||
final MessageBusConnection connection = project.getMessageBus().connect();
|
||||
connection.subscribe(EditorHintListener.TOPIC, listener);
|
||||
assert text != null;
|
||||
@@ -774,12 +758,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
|
||||
boolean sync = ApplicationManager.getApplication().isUnitTestMode() && !CompletionAutoPopupHandler.ourTestingAutopopup;
|
||||
final CompletionThreading strategy = sync ? new SyncCompletion() : new AsyncCompletion();
|
||||
|
||||
strategy.startThread(ProgressWrapper.wrap(this), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scheduleAdvertising();
|
||||
}
|
||||
});
|
||||
strategy.startThread(ProgressWrapper.wrap(this), this::scheduleAdvertising);
|
||||
final WeighingDelegate weigher = strategy.delegateWeighing(this);
|
||||
|
||||
class CalculateItems implements Runnable {
|
||||
@@ -812,12 +791,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
|
||||
}
|
||||
|
||||
public void addAdvertisement(@NotNull final String text, @Nullable final Color bgColor) {
|
||||
myAdvertiserChanges.offer(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myLookup.addAdvertisement(text, bgColor);
|
||||
}
|
||||
});
|
||||
myAdvertiserChanges.offer(() -> myLookup.addAdvertisement(text, bgColor));
|
||||
|
||||
myQueue.queue(myUpdate);
|
||||
}
|
||||
|
||||
+2
-1
@@ -59,6 +59,7 @@ import com.intellij.util.Consumer;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.ui.GraphicsUtil;
|
||||
import com.intellij.util.ui.JBDimension;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -626,7 +627,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
|
||||
|
||||
EditorColorsManager colorsManager = EditorColorsManager.getInstance();
|
||||
EditorColorsScheme scheme = colorsManager.getGlobalScheme();
|
||||
StyleConstants.setFontSize(myFontSizeStyle, scheme.getQuickDocFontSize().getSize());
|
||||
StyleConstants.setFontSize(myFontSizeStyle, JBUI.scale(scheme.getQuickDocFontSize().getSize()));
|
||||
if (Registry.is("documentation.component.editor.font")) {
|
||||
StyleConstants.setFontFamily(myFontSizeStyle, scheme.getEditorFontName());
|
||||
}
|
||||
|
||||
+6
-6
@@ -93,7 +93,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
private final NotNullLazyValue<ContentManager> myContentManager;
|
||||
private InspectionResultsView myView;
|
||||
private Content myContent;
|
||||
private volatile boolean myUseView;
|
||||
private volatile boolean myViewClosed = true;
|
||||
|
||||
@NotNull
|
||||
private AnalysisUIOptions myUIOptions;
|
||||
@@ -319,7 +319,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
myUIOptions = AnalysisUIOptions.getInstance(getProject()).copy();
|
||||
}
|
||||
myUseView = true;
|
||||
myViewClosed = false;
|
||||
super.launchInspections(scope);
|
||||
}
|
||||
|
||||
@@ -589,7 +589,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
if (virtualFile == null) return null;
|
||||
if (isBinary(file)) return null; //do not inspect binary files
|
||||
|
||||
if (!myUseView && !headlessEnvironment) {
|
||||
if (myViewClosed && !headlessEnvironment) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
|
||||
@@ -785,7 +785,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
final ContentManager contentManager = getContentManager();
|
||||
contentManager.removeContent(myContent, true);
|
||||
}
|
||||
myUseView = false;
|
||||
myViewClosed = true;
|
||||
myView = null;
|
||||
super.close(noSuspisiousCodeFound);
|
||||
}
|
||||
@@ -977,7 +977,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
return file instanceof PsiBinaryFile || file.getFileType().isBinary();
|
||||
}
|
||||
|
||||
public boolean useView() {
|
||||
return myUseView;
|
||||
public boolean isViewClosed() {
|
||||
return myViewClosed;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -329,7 +329,8 @@ public abstract class InspectionRVContentProvider {
|
||||
}
|
||||
}
|
||||
else if (current instanceof RefElementNode) {
|
||||
if (((RefElementNode)current).getElement().getName().compareTo(((RefElementNode)child).getElement().getName()) == 0) {
|
||||
if (((RefElementNode)current).getElement().getName().compareTo(((RefElementNode)child).getElement().getName()) == 0 &&
|
||||
((RefElementNode)current).getElement().getQualifiedName().compareTo(((RefElementNode)child).getElement().getQualifiedName()) == 0) {
|
||||
processDepth(model, child, current);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@ import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -170,6 +173,15 @@ public class QuickFixAction extends AnAction {
|
||||
}, templatePresentationText, null);
|
||||
|
||||
refreshViews(project, ignoredElements, myToolWrapper);
|
||||
final InspectionTree tree = context.getView().getTree();
|
||||
final TreePath[] selected = tree.getSelectionPaths();
|
||||
if (selected != null) {
|
||||
for (TreePath path : selected) {
|
||||
path.getLastPathComponent();
|
||||
((DefaultTreeModel) tree.getModel()).reload((TreeNode)path.getLastPathComponent());
|
||||
}
|
||||
}
|
||||
tree.restoreExpansionAndSelection();
|
||||
}
|
||||
finally { //to make offline view lazy
|
||||
if (initial) refManager.inspectionReadActionStarted();
|
||||
|
||||
+24
-9
@@ -222,7 +222,7 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
}
|
||||
|
||||
final GlobalInspectionContextImpl context = getContext();
|
||||
if (!context.useView() || !(refElement instanceof RefElement)) {
|
||||
if (context.isViewClosed() || !(refElement instanceof RefElement)) {
|
||||
return;
|
||||
}
|
||||
if (myToolWrapper instanceof LocalInspectionToolWrapper) {
|
||||
@@ -393,24 +393,34 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
if (descriptors != null) {
|
||||
ArrayList<CommonProblemDescriptor> newDescriptors = new ArrayList<CommonProblemDescriptor>(Arrays.asList(descriptors));
|
||||
newDescriptors.remove(problem);
|
||||
CommonProblemDescriptor[] newDescriptorsAsArray = newDescriptors.toArray(new CommonProblemDescriptor[newDescriptors.size()]);
|
||||
getQuickFixActions().put(refEntity, null);
|
||||
if (!newDescriptors.isEmpty()) {
|
||||
problemElements.put(refEntity, newDescriptors.toArray(new CommonProblemDescriptor[newDescriptors.size()]));
|
||||
problemElements.put(refEntity, newDescriptorsAsArray);
|
||||
for (CommonProblemDescriptor descriptor : newDescriptors) {
|
||||
collectQuickFixes(descriptor.getFixes(), refEntity);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ignoreProblemElement(refEntity);
|
||||
}
|
||||
ignoreProblemElement(refEntity, newDescriptorsAsArray, problem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ignoreProblemElement(RefEntity refEntity){
|
||||
final CommonProblemDescriptor[] problemDescriptors = getProblemElements().remove(refEntity);
|
||||
getIgnoredElements().put(refEntity, problemDescriptors);
|
||||
private void ignoreProblemElement(RefEntity refEntity, CommonProblemDescriptor[] newDescriptors, CommonProblemDescriptor toIgnore){
|
||||
if (newDescriptors != null && newDescriptors.length == 0) {
|
||||
newDescriptors = null;
|
||||
}
|
||||
if (newDescriptors == null) {
|
||||
getProblemElements().remove(refEntity);
|
||||
} else {
|
||||
getProblemElements().put(refEntity, newDescriptors);
|
||||
}
|
||||
CommonProblemDescriptor[] oldIgnored = getIgnoredElements().getOrDefault(refEntity, CommonProblemDescriptor.EMPTY_ARRAY);
|
||||
CommonProblemDescriptor[] update = new CommonProblemDescriptor[oldIgnored.length + 1];
|
||||
System.arraycopy(oldIgnored, 0, update, 0, oldIgnored.length);
|
||||
update[update.length - 1] = toIgnore;
|
||||
getIgnoredElements().put(refEntity, update);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -594,7 +604,7 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
myModulesProblems.add((RefModule)element);
|
||||
}
|
||||
else {
|
||||
String groupName = element instanceof RefElement ? element.getRefManager().getGroupName((RefElement)element) : null;
|
||||
String groupName = element instanceof RefElement ? element.getRefManager().getGroupName((RefElement)element) : element.getQualifiedName() ;
|
||||
Set<RefEntity> content = myContents.get(groupName);
|
||||
if (content == null) {
|
||||
content = new HashSet<RefEntity>();
|
||||
@@ -733,6 +743,11 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
public boolean isElementIgnored(final RefEntity element) {
|
||||
for (RefEntity entity : getIgnoredElements().keySet()) {
|
||||
if (Comparing.equal(entity, element)) {
|
||||
for (RefEntity entity1 : getProblemElements().keySet()) {
|
||||
if (Comparing.equal(entity1, element)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class InspectionNodeInfo extends JPanel {
|
||||
|
||||
public InspectionNodeInfo(final InspectionToolWrapper toolWrapper, Project project) {
|
||||
setLayout(new GridBagLayout());
|
||||
setBorder(IdeBorderFactory.createEmptyBorder(5, 3, 0, 0));
|
||||
setBorder(IdeBorderFactory.createEmptyBorder(5, 12, 0, 0));
|
||||
myProject = project;
|
||||
myTitle = new SimpleColoredComponent();
|
||||
myCurrentProfile = (InspectionProfileImpl)InspectionProjectProfileManager.getInstance(project).getProjectProfileImpl();
|
||||
@@ -55,7 +55,7 @@ public class InspectionNodeInfo extends JPanel {
|
||||
myButton = new JButton();
|
||||
|
||||
add(myTitle,
|
||||
new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new JBInsets(0, 2, 0, 0),
|
||||
new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),
|
||||
0, 0));
|
||||
|
||||
JEditorPane description = new JEditorPane();
|
||||
@@ -64,14 +64,14 @@ public class InspectionNodeInfo extends JPanel {
|
||||
description.setOpaque(false);
|
||||
description.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE);
|
||||
final String toolDescription = toolWrapper.loadDescription();
|
||||
SingleInspectionProfilePanel.readHTML(description, SingleInspectionProfilePanel.toHTML(description, toolDescription == null ? "" : toolDescription, true));
|
||||
SingleInspectionProfilePanel.readHTML(description, SingleInspectionProfilePanel.toHTML(description, toolDescription == null ? "" : toolDescription, false));
|
||||
|
||||
add(ScrollPaneFactory.createScrollPane(description, true),
|
||||
new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH,
|
||||
new JBInsets(5, 5, 0, 0), 0, 0));
|
||||
new Insets(0, 0, 0, 0), 0, 0));
|
||||
add(myButton,
|
||||
new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
|
||||
new JBInsets(15, 0, 0, 0), 0, 0));
|
||||
new Insets(15, 0, 0, 0), 0, 0));
|
||||
updateEnableButtonText(false);
|
||||
|
||||
new ClickListener() {
|
||||
@@ -99,9 +99,9 @@ public class InspectionNodeInfo extends JPanel {
|
||||
}
|
||||
myButton.setText((isEnabled ? "Disable" : "Enable") + " inspection");
|
||||
myTitle.clear();
|
||||
myTitle.append(myName, SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
|
||||
myTitle.append(myName + " inspection", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
|
||||
if (!isEnabled) {
|
||||
myTitle.append(" Disabled", SimpleTextAttributes.GRAYED_ATTRIBUTES);
|
||||
myTitle.append(" Disabled", SimpleTextAttributes.GRAYED_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
private static final Logger LOG = Logger.getInstance(InspectionResultsView.class);
|
||||
|
||||
public static final DataKey<InspectionResultsView> DATA_KEY = DataKey.create("inspectionView");
|
||||
private static final Key<Boolean> PREVIEW_EDITOR_IS_REUSED_KEY = Key.create("inspection.tool.window.preview.editor.is.reused.");
|
||||
private static final Key<Boolean> PREVIEW_EDITOR_IS_REUSED_KEY = Key.create("inspection.tool.window.preview.editor.is.reused");
|
||||
|
||||
private final Project myProject;
|
||||
private final InspectionTree myTree;
|
||||
@@ -627,7 +627,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
severityGroupNode = ConcurrencyUtil.cacheOrGet(mySeverityGroupNodes, level, newNode);
|
||||
if (severityGroupNode == newNode) {
|
||||
InspectionTreeNode root = myTree.getRoot();
|
||||
insertByIndex(root, severityGroupNode);
|
||||
insertByIndex(severityGroupNode, root);
|
||||
}
|
||||
}
|
||||
return severityGroupNode;
|
||||
|
||||
+14
-3
@@ -80,7 +80,11 @@ public class InspectionResultsViewComparator implements Comparator {
|
||||
if (node2 instanceof InspectionModuleNode) return 1;
|
||||
|
||||
if (node1 instanceof InspectionPackageNode && node2 instanceof InspectionPackageNode) {
|
||||
return ((InspectionPackageNode)node1).getPackageName().compareToIgnoreCase(((InspectionPackageNode)node2).getPackageName());
|
||||
final int nonQualified = ((InspectionPackageNode)node1).getPackageName().compareToIgnoreCase(((InspectionPackageNode)node2).getPackageName());
|
||||
if (nonQualified != 0) {
|
||||
return nonQualified;
|
||||
}
|
||||
return nonQualified;
|
||||
}
|
||||
if (node1 instanceof InspectionPackageNode) return -1;
|
||||
if (node2 instanceof InspectionPackageNode) return 1;
|
||||
@@ -159,10 +163,17 @@ public class InspectionResultsViewComparator implements Comparator {
|
||||
|
||||
private static int compareEntities(final RefEntity entity1, final RefEntity entity2) {
|
||||
if (entity1 instanceof RefElement && entity2 instanceof RefElement) {
|
||||
return PsiUtilCore.compareElementsByPosition(((RefElement)entity1).getElement(), ((RefElement)entity2).getElement());
|
||||
final int positionComparing = PsiUtilCore.compareElementsByPosition(((RefElement)entity1).getElement(), ((RefElement)entity2).getElement());
|
||||
if (positionComparing != 0) {
|
||||
return positionComparing;
|
||||
}
|
||||
}
|
||||
if (entity1 != null && entity2 != null) {
|
||||
return entity1.getName().compareToIgnoreCase(entity2.getName());
|
||||
final int nameComparing = entity1.getName().compareToIgnoreCase(entity2.getName());
|
||||
if (nameComparing != 0) {
|
||||
return nameComparing;
|
||||
}
|
||||
return entity1.getQualifiedName().compareToIgnoreCase(entity2.getQualifiedName());
|
||||
}
|
||||
if (entity1 != null) return -1;
|
||||
return entity2 != null ? 1 : 0;
|
||||
|
||||
@@ -31,7 +31,9 @@ import com.intellij.ui.ClickListener;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.SimpleColoredComponent;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.util.ui.JBInsets;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -39,6 +41,7 @@ import javax.swing.*;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
@@ -57,7 +60,7 @@ public class QuickFixToolbar extends JPanel {
|
||||
final boolean multipleDescriptors = problemCount > 1;
|
||||
|
||||
setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
||||
setBorder(IdeBorderFactory.createEmptyBorder(hasFixes ? 0 : 5, 5, 0, 0));
|
||||
setBorder(IdeBorderFactory.createEmptyBorder(7 + (hasFixes ? 0 : 5), hasFixes ? 12 : 9, hasFixes ? 0 : 6, 0));
|
||||
|
||||
fill(multipleDescriptors, () -> getLabel(fixes, tree.getSelectionCount() == 1 ? (InspectionTreeNode)tree.getSelectionPath().getLastPathComponent() : null, problemCount), this);
|
||||
fill(hasFixes, () -> createFixPanel(fixes, multipleDescriptors), this);
|
||||
@@ -74,11 +77,11 @@ public class QuickFixToolbar extends JPanel {
|
||||
label.append(problemsCount + " problems" +
|
||||
(targetName == null ? "" : (" in " + targetName)) +
|
||||
(problemsCount > 1 && (fixes != null && fixes.length == MAX_FIX_COUNT) ? " Fix all:" : "") +
|
||||
(hasFixesNonIntersectedFixes ? ":" : "" ),
|
||||
SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
|
||||
(hasFixesNonIntersectedFixes ? ":" : "" ));
|
||||
if (hasFixesNonIntersectedFixes) {
|
||||
label.append(" select a single problem to see its quick fixes");
|
||||
}
|
||||
label.setBorder(IdeBorderFactory.createEmptyBorder(0, 0, 0, 2));
|
||||
return label;
|
||||
}
|
||||
|
||||
@@ -86,16 +89,18 @@ public class QuickFixToolbar extends JPanel {
|
||||
@NotNull final TreePath[] paths,
|
||||
@NotNull final Project project,
|
||||
boolean multipleDescriptors) {
|
||||
final AnAction[] suppressors = new SuppressActionWrapper(project, toolWrapper, paths).getChildren(null);
|
||||
final ComboBoxAction action = new ComboBoxAction() {
|
||||
{
|
||||
getTemplatePresentation().setText(multipleDescriptors ? "Suppress All" : "Suppress");
|
||||
getTemplatePresentation().setEnabledAndVisible(suppressors.length != 0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
|
||||
DefaultActionGroup group = new DefaultActionGroup();
|
||||
group.addAll(new SuppressActionWrapper(project, toolWrapper, paths).getChildren(null));
|
||||
group.addAll(suppressors);
|
||||
return group;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -77,7 +77,7 @@ public class RefElementNode extends InspectionTreeNode {
|
||||
if (element == null || !element.isValid()) {
|
||||
return InspectionsBundle.message("inspection.reference.invalid");
|
||||
}
|
||||
return element.getRefManager().getRefinedElement(element).getQualifiedName();
|
||||
return element.getRefManager().getRefinedElement(element).getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import gnu.trove.TIntArrayList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -132,14 +133,7 @@ public class ConsoleBuffer {
|
||||
}
|
||||
|
||||
public static int getLegacyCycleBufferSize() {
|
||||
String cycleBufferSizeProperty = System.getProperty("idea.cycle.buffer.size");
|
||||
if (cycleBufferSizeProperty == null) return 1024 * 1024;
|
||||
try {
|
||||
return Integer.parseInt(cycleBufferSizeProperty) * 1024;
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return 1024 * 1024;
|
||||
}
|
||||
return SystemProperties.getIntProperty("idea.cycle.buffer.size", 1024) * 1024;
|
||||
}
|
||||
|
||||
public boolean isUseCyclicBuffer() {
|
||||
|
||||
@@ -85,7 +85,7 @@ public class RunContentBuilder extends RunTab {
|
||||
}
|
||||
initLogConsoles(profile, contentDescriptor, console);
|
||||
}
|
||||
myUi.getOptions().setLeftToolbar(createActionToolbar(contentDescriptor), ActionPlaces.UNKNOWN);
|
||||
myUi.getOptions().setLeftToolbar(createActionToolbar(contentDescriptor), ActionPlaces.RUNNER_TOOLBAR);
|
||||
|
||||
if (profile instanceof RunConfigurationBase) {
|
||||
if (console instanceof ObservableConsoleView && !ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
@@ -131,7 +131,7 @@ public class RunContentBuilder extends RunTab {
|
||||
}
|
||||
}
|
||||
|
||||
consoleContent.setActions(consoleActions, ActionPlaces.UNKNOWN, console.getComponent());
|
||||
consoleContent.setActions(consoleActions, ActionPlaces.RUNNER_TOOLBAR, console.getComponent());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -871,7 +871,8 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
|
||||
|
||||
final AnAction[] actions = groupToBuild.getChildren(null);
|
||||
if (!Arrays.equals(actions, myContextActions.get(entry.getKey()))) {
|
||||
ActionToolbar tb = myActionManager.createActionToolbar(myActionsPlace, groupToBuild, true);
|
||||
String adjustedPlace = myActionsPlace == ActionPlaces.UNKNOWN ? ActionPlaces.TOOLBAR : myActionsPlace;
|
||||
ActionToolbar tb = myActionManager.createActionToolbar(adjustedPlace, groupToBuild, true);
|
||||
tb.getComponent().setBorder(null);
|
||||
tb.setTargetComponent(contextComponent);
|
||||
eachPlaceholder.setContent(tb.getComponent());
|
||||
|
||||
@@ -169,13 +169,13 @@ public abstract class LRUPopupBuilder<T> {
|
||||
new BaseListPopupStep<T>(myTitle, combinedItems) {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getTextFor(@NotNull T t) {
|
||||
return getPresentation(t).first;
|
||||
public String getTextFor(T t) {
|
||||
return t == null ? "" : getPresentation(t).first;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIconFor(@NotNull T t) {
|
||||
return getPresentation(t).second;
|
||||
public Icon getIconFor(T t) {
|
||||
return t == null ? null : getPresentation(t).second;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -62,6 +62,4 @@ public abstract class RootDetector {
|
||||
*/
|
||||
@NotNull
|
||||
public abstract Collection<VirtualFile> detectRoots(@NotNull VirtualFile rootCandidate, @NotNull ProgressIndicator progressIndicator);
|
||||
|
||||
public static ExtensionPointName<RootDetector> JAVA_SOURCE_ROOT_DETECTOR = ExtensionPointName.create("com.intellij.library.javaSourceRootDetector");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -171,7 +171,7 @@ public class RegistryUi implements Disposable {
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(!myTable.isEditing() && myTable.getSelectedRow() >= 0);
|
||||
e.getPresentation().setText("Revert to Default");
|
||||
e.getPresentation().setIcon(AllIcons.General.Remove);
|
||||
e.getPresentation().setIcon(AllIcons.General.Reset);
|
||||
|
||||
if (e.getPresentation().isEnabled()) {
|
||||
final RegistryValue rv = myModel.getRegistryValue(myTable.getSelectedRow());
|
||||
|
||||
@@ -56,14 +56,14 @@ import java.util.List;
|
||||
|
||||
//todo listen & notifyListeners readonly events?
|
||||
public class PsiDocumentManagerImpl extends PsiDocumentManagerBase implements SettingsSavingComponent {
|
||||
private final DocumentCommitThread myDocumentCommitThread;
|
||||
private final DocumentCommitProcessor myDocumentCommitThread;
|
||||
private final boolean myUnitTestMode = ApplicationManager.getApplication().isUnitTestMode();
|
||||
|
||||
public PsiDocumentManagerImpl(@NotNull final Project project,
|
||||
@NotNull PsiManager psiManager,
|
||||
@NotNull EditorFactory editorFactory,
|
||||
@NotNull MessageBus bus,
|
||||
@NonNls @NotNull final DocumentCommitThread documentCommitThread) {
|
||||
@NonNls @NotNull final DocumentCommitProcessor documentCommitThread) {
|
||||
super(project, psiManager, bus, documentCommitThread);
|
||||
myDocumentCommitThread = documentCommitThread;
|
||||
editorFactory.getEventMulticaster().addDocumentListener(this, project);
|
||||
@@ -71,19 +71,15 @@ public class PsiDocumentManagerImpl extends PsiDocumentManagerBase implements Se
|
||||
busConnection.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter() {
|
||||
@Override
|
||||
public void fileContentLoaded(@NotNull final VirtualFile virtualFile, @NotNull Document document) {
|
||||
PsiFile psiFile = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() {
|
||||
@Override
|
||||
public PsiFile compute() {
|
||||
return myProject.isDisposed() || !virtualFile.isValid() ? null : getCachedPsiFile(virtualFile);
|
||||
}
|
||||
});
|
||||
PsiFile psiFile = ApplicationManager.getApplication().runReadAction(
|
||||
(Computable<PsiFile>)() -> myProject.isDisposed() || !virtualFile.isValid() ? null : getCachedPsiFile(virtualFile));
|
||||
fireDocumentCreated(document, psiFile);
|
||||
}
|
||||
});
|
||||
busConnection.subscribe(DocumentBulkUpdateListener.TOPIC, new DocumentBulkUpdateListener.Adapter() {
|
||||
@Override
|
||||
public void updateFinished(@NotNull Document doc) {
|
||||
documentCommitThread.queueCommit(project, doc, "Bulk update finished", ApplicationManager.getApplication().getDefaultModalityState());
|
||||
documentCommitThread.commitAsynchronously(project, doc, "Bulk update finished", ApplicationManager.getApplication().getDefaultModalityState());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -161,15 +157,12 @@ public class PsiDocumentManagerImpl extends PsiDocumentManagerBase implements Se
|
||||
@Override
|
||||
public void save() {
|
||||
// Ensure all documents are committed on save so file content dependent indices, that use PSI to build have consistent content.
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
commitAllDocuments();
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
UIUtil.invokeLaterIfNeeded(() -> {
|
||||
try {
|
||||
commitAllDocuments();
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -178,7 +171,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManagerBase implements Se
|
||||
@TestOnly
|
||||
public void clearUncommittedDocuments() {
|
||||
super.clearUncommittedDocuments();
|
||||
myDocumentCommitThread.clearQueue();
|
||||
((DocumentCommitThread)myDocumentCommitThread).clearQueue();
|
||||
}
|
||||
|
||||
@NonNls
|
||||
|
||||
+2
-2
@@ -39,7 +39,7 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.DebugUtil;
|
||||
import com.intellij.psi.impl.DocumentCommitProcessor;
|
||||
import com.intellij.psi.impl.DocumentCommitThread;
|
||||
import com.intellij.psi.impl.PsiDocumentManagerBase;
|
||||
import com.intellij.psi.impl.smartPointers.SmartPointerManagerImpl;
|
||||
import com.intellij.psi.impl.source.PsiFileImpl;
|
||||
@@ -467,7 +467,7 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
try {
|
||||
final DiffLog diffLog = BlockSupportImpl.mergeTrees(oldFile, oldFileNode, injectedNode, new DaemonProgressIndicator(),
|
||||
oldFileNode.getText());
|
||||
DocumentCommitProcessor.doActualPsiChange(oldFile, diffLog);
|
||||
DocumentCommitThread.doActualPsiChange(oldFile, diffLog);
|
||||
}
|
||||
finally {
|
||||
DebugUtil.finishPsiModification();
|
||||
|
||||
@@ -26,7 +26,6 @@ import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.project.DumbModePermission;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.*;
|
||||
@@ -188,7 +187,9 @@ public class SafeDeleteProcessor extends BaseRefactoringProcessor {
|
||||
for (PsiElement element : myElements) {
|
||||
for(SafeDeleteProcessorDelegate delegate: Extensions.getExtensions(SafeDeleteProcessorDelegate.EP_NAME)) {
|
||||
if (delegate.handlesElement(element)) {
|
||||
Collection<String> foundConflicts = delegate.findConflicts(element, myElements);
|
||||
Collection<String> foundConflicts = delegate instanceof SafeDeleteProcessorDelegateBase
|
||||
? ((SafeDeleteProcessorDelegateBase)delegate).findConflicts(element, myElements, usages)
|
||||
: delegate.findConflicts(element, myElements);
|
||||
if (foundConflicts != null) {
|
||||
conflicts.addAll(foundConflicts);
|
||||
}
|
||||
|
||||
+4
@@ -42,4 +42,8 @@ public abstract class SafeDeleteProcessorDelegateBase implements SafeDeleteProce
|
||||
public UsageView showUsages(UsageInfo[] usages, UsageViewPresentation presentation, UsageViewManager manager, PsiElement[] elements) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Collection<String> findConflicts(PsiElement element, PsiElement[] elements, UsageInfo[] usages) {
|
||||
return findConflicts(element, elements);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
*/
|
||||
package com.intellij.openapi.actionSystem;
|
||||
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Possible places in the IDEA user interface where an action can appear.
|
||||
*/
|
||||
@@ -25,6 +27,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public abstract class ActionPlaces {
|
||||
public static final String UNKNOWN = "unknown";
|
||||
public static final String TOOLBAR = "toolbar";
|
||||
|
||||
/**
|
||||
* consider to use {@link #isMainMenuOrActionSearch(String)} instead
|
||||
@@ -63,13 +66,13 @@ public abstract class ActionPlaces {
|
||||
public static final String CALL_HIERARCHY_VIEW_TOOLBAR = "CallHierarchyViewToolbar";
|
||||
public static final String J2EE_ATTRIBUTES_VIEW_POPUP = "J2EEAttributesViewPopup";
|
||||
public static final String J2EE_VIEW_POPUP = "J2EEViewPopup";
|
||||
public static final String RUNNER_TOOLBAR = "RunnerToolbar";
|
||||
public static final String DEBUGGER_TOOLBAR = "DebuggerToolbar";
|
||||
public static final String USAGE_VIEW_POPUP = "UsageViewPopup";
|
||||
public static final String USAGE_VIEW_TOOLBAR = "UsageViewToolbar";
|
||||
public static final String STRUCTURE_VIEW_POPUP = "StructureViewPopup";
|
||||
public static final String STRUCTURE_VIEW_TOOLBAR = "StructureViewToolbar";
|
||||
public static final String NAVIGATION_BAR_POPUP = "NavBar";
|
||||
@Deprecated public static final String NAVIGATION_BAR = NAVIGATION_BAR_POPUP;
|
||||
public static final String NAVIGATION_BAR_TOOLBAR = "NavBarToolbar";
|
||||
|
||||
public static final String TODO_VIEW_POPUP = "TodoViewPopup";
|
||||
@@ -128,22 +131,25 @@ public abstract class ActionPlaces {
|
||||
public static final String V8_HEAP_PROFILING_POPUP = "V8_HEAP_PROFILING_POPUP";
|
||||
public static final String V8_HEAP_DIFF_PROFILING_POPUP = "V8_HEAP_DIFF_PROFILING_POPUP";
|
||||
|
||||
private static final String[] ourToolbarPlaces = {EDITOR_TOOLBAR, PROJECT_VIEW_TOOLBAR, TESTTREE_VIEW_TOOLBAR, MAIN_TOOLBAR,
|
||||
private static final Set<String> ourToolbarPlaces = ContainerUtil.newHashSet(
|
||||
EDITOR_TOOLBAR, PROJECT_VIEW_TOOLBAR, TESTTREE_VIEW_TOOLBAR, MAIN_TOOLBAR, TOOLBAR, RUNNER_TOOLBAR,
|
||||
ANT_EXPLORER_TOOLBAR, ANT_MESSAGES_TOOLBAR, COMPILER_MESSAGES_TOOLBAR, TODO_VIEW_TOOLBAR, STRUCTURE_VIEW_TOOLBAR, USAGE_VIEW_TOOLBAR,
|
||||
DEBUGGER_TOOLBAR, CALL_HIERARCHY_VIEW_TOOLBAR, METHOD_HIERARCHY_VIEW_TOOLBAR, TYPE_HIERARCHY_VIEW_TOOLBAR, JAVADOC_TOOLBAR,
|
||||
FILE_HISTORY_TOOLBAR, FILEHISTORY_VIEW_TOOLBAR, LVCS_DIRECTORY_HISTORY_TOOLBAR, CHANGES_VIEW_TOOLBAR, PHING_EXPLORER_TOOLBAR,
|
||||
PHING_MESSAGES_TOOLBAR, ANALYZE_STACKTRACE_PANEL_TOOLBAR};
|
||||
PHING_MESSAGES_TOOLBAR, ANALYZE_STACKTRACE_PANEL_TOOLBAR
|
||||
);
|
||||
|
||||
|
||||
public static boolean isToolbarPlace(@NotNull String place) {
|
||||
return ArrayUtil.find(ourToolbarPlaces, place) != -1;
|
||||
return ourToolbarPlaces.contains(place);
|
||||
}
|
||||
|
||||
public static boolean isMainMenuOrActionSearch(String place) {
|
||||
return MAIN_MENU.equals(place) || ACTION_SEARCH.equals(place);
|
||||
}
|
||||
|
||||
private static final String[] ourPopupPlaces = {EDITOR_POPUP, EDITOR_TAB_POPUP, COMMANDER_POPUP,
|
||||
private static final Set<String> ourPopupPlaces = ContainerUtil.newHashSet(
|
||||
EDITOR_POPUP, EDITOR_TAB_POPUP, COMMANDER_POPUP,
|
||||
PROJECT_VIEW_POPUP, FAVORITES_VIEW_POPUP, SCOPE_VIEW_POPUP, TESTTREE_VIEW_POPUP, TESTSTATISTICS_VIEW_POPUP, TYPE_HIERARCHY_VIEW_POPUP,
|
||||
METHOD_HIERARCHY_VIEW_POPUP, CALL_HIERARCHY_VIEW_POPUP, J2EE_ATTRIBUTES_VIEW_POPUP, J2EE_VIEW_POPUP, USAGE_VIEW_POPUP,
|
||||
STRUCTURE_VIEW_POPUP, TODO_VIEW_POPUP, COMPILER_MESSAGES_POPUP, ANT_MESSAGES_POPUP, ANT_EXPLORER_POPUP, UPDATE_POPUP,
|
||||
@@ -152,9 +158,9 @@ public abstract class ActionPlaces {
|
||||
CREATE_EJB_POPUP, CHANGES_VIEW_POPUP, REMOTE_HOST_VIEW_POPUP, REMOTE_HOST_DIALOG_POPUP, TFS_TREE_POPUP,
|
||||
ACTION_PLACE_VCS_QUICK_LIST_POPUP_ACTION, PHING_EXPLORER_POPUP, NAVIGATION_BAR_POPUP, JS_BUILD_TOOL_POPUP, DIFF_TOOLBAR,
|
||||
V8_CPU_PROFILING_POPUP, V8_HEAP_PROFILING_POPUP, V8_HEAP_PROFILING_POPUP
|
||||
};
|
||||
);
|
||||
|
||||
public static boolean isPopupPlace(@NotNull String place) {
|
||||
return ArrayUtil.find(ourPopupPlaces, place) != -1;
|
||||
return ourPopupPlaces.contains(place);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,8 +147,9 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
|
||||
|
||||
public ComboBoxButton(Presentation presentation) {
|
||||
myPresentation = presentation;
|
||||
setEnabled(myPresentation.isEnabled());
|
||||
setModel(new MyButtonModel());
|
||||
getModel().setEnabled(myPresentation.isEnabled());
|
||||
setVisible(presentation.isVisible());
|
||||
setHorizontalAlignment(LEFT);
|
||||
setFocusable(false);
|
||||
if (isSmallVariant()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,23 +18,22 @@ package com.intellij.openapi.ui;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.util.ui.Animator;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public class DialogEarthquakeShaker {
|
||||
private JDialog myDialog;
|
||||
private Window myWindow;
|
||||
private Point myNaturalLocation;
|
||||
private long myStartTime;
|
||||
|
||||
private DialogEarthquakeShaker(JDialog dialog) {
|
||||
myDialog = dialog;
|
||||
private DialogEarthquakeShaker(Window window) {
|
||||
myWindow = window;
|
||||
}
|
||||
|
||||
public void startShake() {
|
||||
myNaturalLocation = myDialog.getLocation();
|
||||
myNaturalLocation = myWindow.getLocation();
|
||||
myStartTime = System.currentTimeMillis();
|
||||
new Animator("EarthQuake", 10, 70, true) {
|
||||
@Override
|
||||
@@ -43,19 +42,19 @@ public class DialogEarthquakeShaker {
|
||||
final double waveOffset = (elapsed % 70) / 70d;
|
||||
final double angle = waveOffset * 2d * Math.PI;
|
||||
final int shakenX = (int)((Math.sin(angle) * 10) + myNaturalLocation.x);
|
||||
myDialog.setLocation(shakenX, myNaturalLocation.y);
|
||||
myDialog.repaint();
|
||||
myWindow.setLocation(shakenX, myNaturalLocation.y);
|
||||
myWindow.repaint();
|
||||
if (elapsed > 150) {
|
||||
suspend();
|
||||
myDialog.setLocation(myNaturalLocation);
|
||||
myDialog.repaint();
|
||||
myWindow.setLocation(myNaturalLocation);
|
||||
myWindow.repaint();
|
||||
Disposer.dispose(this);
|
||||
}
|
||||
}
|
||||
}.resume();
|
||||
}
|
||||
|
||||
public static void shake(JDialog dialog) {
|
||||
new DialogEarthquakeShaker(dialog).startShake();
|
||||
public static void shake(Window window) {
|
||||
new DialogEarthquakeShaker(window).startShake();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ public abstract class IdeFocusManager implements FocusRequestor {
|
||||
public abstract Component getFocusOwner();
|
||||
|
||||
/**
|
||||
* Runs runnable for whicj <code>DataContext</code> will no be computed from the current focus owner,
|
||||
* Runs runnable for which <code>DataContext</code> will no be computed from the current focus owner,
|
||||
* but used the given one
|
||||
*/
|
||||
public abstract void runOnOwnContext(@NotNull DataContext context, @NotNull Runnable runnable);
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||
import com.intellij.util.concurrency.EdtExecutorService;
|
||||
import com.intellij.util.concurrency.QueueProcessor;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
@@ -52,8 +53,8 @@ public class Alarm implements Disposable {
|
||||
|
||||
private volatile boolean myDisposed;
|
||||
|
||||
private final List<Request> myRequests = new SmartList<Request>(); // guarded by LOCK
|
||||
private final List<Request> myPendingRequests = new SmartList<Request>(); // guarded by LOCK
|
||||
private final List<Request> myRequests = new SmartList<>(); // guarded by LOCK
|
||||
private final List<Request> myPendingRequests = new SmartList<>(); // guarded by LOCK
|
||||
|
||||
private final ScheduledExecutorService myExecutorService;
|
||||
|
||||
@@ -68,7 +69,9 @@ public class Alarm implements Disposable {
|
||||
myDisposed = true;
|
||||
cancelAllRequests();
|
||||
|
||||
myExecutorService.shutdownNow();
|
||||
if (myThreadToUse != ThreadToUse.SWING_THREAD) {
|
||||
myExecutorService.shutdownNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +126,12 @@ public class Alarm implements Disposable {
|
||||
public Alarm(@NotNull ThreadToUse threadToUse, @Nullable Disposable parentDisposable) {
|
||||
myThreadToUse = threadToUse;
|
||||
|
||||
myExecutorService = // have to restrict the number of running tasks because otherwise the (implicit) contract of
|
||||
myExecutorService = threadToUse == ThreadToUse.SWING_THREAD ?
|
||||
// pass straight to EDT
|
||||
EdtExecutorService.getScheduledExecutorInstance() :
|
||||
|
||||
// or pass to app pooled thread.
|
||||
// have to restrict the number of running tasks because otherwise the (implicit) contract of
|
||||
// "addRequests with the same delay are executed in order" will be broken
|
||||
AppExecutorUtil.createBoundedScheduledExecutorService(1);
|
||||
|
||||
@@ -258,7 +266,7 @@ public class Alarm implements Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
requests = new SmartList<Pair<Request, Runnable>>();
|
||||
requests = new SmartList<>();
|
||||
for (Request request : myRequests) {
|
||||
Runnable existingTask = request.cancel();
|
||||
if (existingTask != null) {
|
||||
@@ -280,7 +288,7 @@ public class Alarm implements Disposable {
|
||||
void waitForAllExecuted(long timeout, @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
List<Request> requests;
|
||||
synchronized (LOCK) {
|
||||
requests = new ArrayList<Request>(myRequests);
|
||||
requests = new ArrayList<>(myRequests);
|
||||
}
|
||||
|
||||
for (Request request : requests) {
|
||||
@@ -357,12 +365,9 @@ public class Alarm implements Disposable {
|
||||
|
||||
if (myThreadToUse == ThreadToUse.SWING_THREAD && !isEdt()) {
|
||||
//noinspection SSBasedInspection
|
||||
EdtInvocationManager.getInstance().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!myDisposed) {
|
||||
QueueProcessor.runSafely(task);
|
||||
}
|
||||
EdtInvocationManager.getInstance().invokeLater(() -> {
|
||||
if (!myDisposed) {
|
||||
QueueProcessor.runSafely(task);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@ package com.intellij.execution.process;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
public class ProcessInfo {
|
||||
@@ -24,6 +29,7 @@ public class ProcessInfo {
|
||||
|
||||
private final int myPid;
|
||||
@NotNull private final String myCommandLine;
|
||||
@NotNull private final Optional<String> myExecutablePath;
|
||||
@NotNull private final String myExecutableName;
|
||||
@NotNull private final String myArgs;
|
||||
|
||||
@@ -33,10 +39,23 @@ public class ProcessInfo {
|
||||
@NotNull String args) {
|
||||
myPid = pid;
|
||||
myCommandLine = commandLine;
|
||||
myExecutablePath = Optional.empty();
|
||||
myExecutableName = executableName;
|
||||
myArgs = args;
|
||||
}
|
||||
|
||||
public ProcessInfo(int pid,
|
||||
@NotNull String commandLine,
|
||||
@NotNull String executableName,
|
||||
@NotNull String args,
|
||||
@Nullable String executablePath) {
|
||||
myPid = pid;
|
||||
myCommandLine = commandLine;
|
||||
myExecutableName = executableName;
|
||||
myExecutablePath = StringUtil.isNotEmpty(executablePath) ? Optional.of(executablePath) : Optional.empty();
|
||||
myArgs = args;
|
||||
}
|
||||
|
||||
public int getPid() {
|
||||
return myPid;
|
||||
}
|
||||
@@ -51,6 +70,18 @@ public class ProcessInfo {
|
||||
return myExecutableName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Optional<String> getExecutableCannonicalPath() {
|
||||
return myExecutablePath.map(s -> {
|
||||
try {
|
||||
return new File(s).getCanonicalPath();
|
||||
}
|
||||
catch (IOException e) {
|
||||
return s;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getExecutableDisplayName() {
|
||||
return StringUtil.trimEnd(myExecutableName, ".exe", true);
|
||||
|
||||
+38
-14
@@ -90,7 +90,7 @@ public class ProcessListUtil {
|
||||
ProcessOutput processOutput = ExecUtil.execAndGetOutput(new GeneralCommandLine(command));
|
||||
int exitCode = processOutput.getExitCode();
|
||||
if (exitCode != 0) {
|
||||
LOG.error("Cannot get process list, 'ps' exited with code " + exitCode + ", stdout:\n"
|
||||
LOG.error("Cannot get process list, 'ps' exited with code " + exitCode + ", stdout:\n"
|
||||
+ processOutput.getStdout()
|
||||
+ "\nstderr:\n"
|
||||
+ processOutput.getStderr());
|
||||
@@ -98,7 +98,7 @@ public class ProcessListUtil {
|
||||
output = processOutput.getStdout();
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
LOG.error("Cannot get process list", e);
|
||||
LOG.error("Cannot get process list", e);
|
||||
return null;
|
||||
}
|
||||
return parser.fun(output);
|
||||
@@ -110,7 +110,7 @@ public class ProcessListUtil {
|
||||
|
||||
File[] processes = proc.listFiles();
|
||||
if (processes == null) {
|
||||
LOG.error("Cannot read /proc, not mounted?");
|
||||
LOG.error("Cannot read /proc, not mounted?");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -137,9 +137,22 @@ public class ProcessListUtil {
|
||||
}
|
||||
if (cmdline.isEmpty()) continue;
|
||||
|
||||
String executablePath = null;
|
||||
|
||||
try {
|
||||
File exe = new File(each, "exe");
|
||||
if (!exe.getAbsolutePath().equals(exe.getCanonicalPath())) {
|
||||
executablePath = exe.getCanonicalPath();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
// couldn't resolve symlink
|
||||
}
|
||||
|
||||
result.add(new ProcessInfo(pid, StringUtil.join(cmdline, " "),
|
||||
PathUtil.getFileName(cmdline.get(0)),
|
||||
StringUtil.join(cmdline.subList(1, cmdline.size()), " ")
|
||||
StringUtil.join(cmdline.subList(1, cmdline.size()), " "),
|
||||
executablePath
|
||||
));
|
||||
}
|
||||
return result;
|
||||
@@ -192,7 +205,7 @@ public class ProcessListUtil {
|
||||
String name = PathUtil.getFileName(command);
|
||||
String args = each.commandLine.substring(command.length()).trim();
|
||||
|
||||
result.add(new ProcessInfo(each.pid, each.commandLine, name, args));
|
||||
result.add(new ProcessInfo(each.pid, each.commandLine, name, args, command));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -219,16 +232,21 @@ public class ProcessListUtil {
|
||||
for (int i = 1; i < lines.length; i++) {
|
||||
String line = lines[i];
|
||||
|
||||
int pid = StringUtil.parseInt(line.substring(0, statStart).trim(), -1);
|
||||
if (pid == -1) continue;
|
||||
try {
|
||||
int pid = StringUtil.parseInt(line.substring(0, statStart).trim(), -1);
|
||||
if (pid == -1) continue;
|
||||
|
||||
String state = line.substring(statStart, userStart).trim();
|
||||
if (state.contains("Z")) continue; // zombie
|
||||
String state = line.substring(statStart, userStart).trim();
|
||||
if (state.contains("Z")) continue; // zombie
|
||||
|
||||
String user = line.substring(userStart, commandStart).trim();
|
||||
String commandLine = line.substring(commandStart).trim();
|
||||
String user = line.substring(userStart, commandStart).trim();
|
||||
String commandLine = line.substring(commandStart).trim();
|
||||
|
||||
result.add(new MacProcessInfo(pid, commandLine, user, state));
|
||||
result.add(new MacProcessInfo(pid, commandLine, user, state));
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error("Can't parse line '" + line + "'", e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -249,7 +267,7 @@ public class ProcessListUtil {
|
||||
|
||||
@Nullable
|
||||
static List<ProcessInfo> getProcessList_WindowsWMIC() {
|
||||
return parseCommandOutput(Arrays.asList("wmic.exe", "path", "win32_process", "get", "Caption,Processid,Commandline"),
|
||||
return parseCommandOutput(Arrays.asList("wmic.exe", "path", "win32_process", "get", "Caption,Processid,Commandline,ExecutablePath"),
|
||||
new NullableFunction<String, List<ProcessInfo>>() {
|
||||
@Nullable
|
||||
@Override
|
||||
@@ -272,12 +290,18 @@ public class ProcessListUtil {
|
||||
int pidStart = header.indexOf("ProcessId");
|
||||
if (pidStart == -1) return null;
|
||||
|
||||
int executablePathStart = header.indexOf("ExecutablePath");
|
||||
if (executablePathStart == -1) return null;
|
||||
|
||||
|
||||
for (int i = 1; i < lines.length; i++) {
|
||||
String line = lines[i];
|
||||
|
||||
int pid = StringUtil.parseInt(line.substring(pidStart, line.length()).trim(), -1);
|
||||
if (pid == -1 || pid == 0) continue;
|
||||
|
||||
String executablePath = line.substring(executablePathStart, pidStart).trim();
|
||||
|
||||
String name = line.substring(0, commandLineStart).trim();
|
||||
if (name.isEmpty()) continue;
|
||||
|
||||
@@ -294,7 +318,7 @@ public class ProcessListUtil {
|
||||
}
|
||||
}
|
||||
|
||||
result.add(new ProcessInfo(pid, commandLine, name, args));
|
||||
result.add(new ProcessInfo(pid, commandLine, name, args, executablePath));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -69,7 +69,6 @@ public class SystemHealthMonitor extends ApplicationComponent.Adapter {
|
||||
public void initComponent() {
|
||||
checkJvm();
|
||||
checkIBus();
|
||||
checkJAyatana();
|
||||
startDiskSpaceMonitoring();
|
||||
}
|
||||
|
||||
@@ -100,16 +99,6 @@ public class SystemHealthMonitor extends ApplicationComponent.Adapter {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
private void checkJAyatana() {
|
||||
if (SystemInfo.isXWindow) {
|
||||
String originalOpts = System.getenv("_ORIGINAL_JAVA_TOOL_OPTIONS");
|
||||
if (originalOpts != null && originalOpts.contains("jayatanaag.jar")) {
|
||||
showNotification("ayatana.menu.warn.message");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showNotification(@PropertyKey(resourceBundle = "messages.IdeBundle") String key) {
|
||||
final String ignoreKey = "ignore." + key;
|
||||
boolean ignored = myProperties.isValueSet(ignoreKey);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user