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
+2
-2
@@ -1,8 +1,7 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Mocks">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/dev/easymock.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/dev/easymockclassextension.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/dev/easymock-3.4.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/dev/jmock-2.5.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/dev/jmock-junit4-2.5.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/dev/jmock-legacy-2.5.1.jar!/" />
|
||||
@@ -10,6 +9,7 @@
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/dev/easymock-3.4-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/dev/jmock-2.5.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/dev/jmock-junit4-2.5.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/dev/jmock-legacy-2.5.1.jar!/" />
|
||||
|
||||
Generated
+2
-2
@@ -1,11 +1,11 @@
|
||||
<component name="libraryTable">
|
||||
<library name="pty4j">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/pty4j-0.7.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/pty4j-0.7.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/src/pty4j-0.7-src.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/src/pty4j-0.7.1-src.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
|
||||
@@ -279,7 +279,7 @@ libraryLicense(name: "Plexus Utils", libraryName: "plexus-utils-1.5.5.jar", vers
|
||||
libraryLicense(name: "pockets", attachedTo: "python-helpers", version: "0.2.4", license: "BSD", url: "http://pockets.readthedocs.org/")
|
||||
libraryLicense(name: "protobuf", version: "2.5.0", license: "New BSD", url: "http://code.google.com/p/protobuf/", licenseUrl: "https://github.com/google/protobuf/blob/master/LICENSE")
|
||||
libraryLicense(name: "proxy-vole", libraryName: "proxy-vole", version: "20131209", license: "New BSD License", url: "http://code.google.com/p/proxy-vole/", licenseUrl: "http://opensource.org/licenses/BSD-3-Clause")
|
||||
libraryLicense(name: "pty4j", libraryName: "pty4j", version: "0.7", license: "Eclipse Public License v1.0", url: "https://github.com/traff/pty4j")
|
||||
libraryLicense(name: "pty4j", libraryName: "pty4j", version: "0.7.1", license: "Eclipse Public License v1.0", url: "https://github.com/traff/pty4j")
|
||||
libraryLicense(name: "PureJavaComm", libraryName: "purejavacomm", version: "0.0.16", license: "BSD", url: "http://www.sparetimelabs.com/purejavacomm")
|
||||
libraryLicense(name: "ReflectASM", libraryName: "reflectasm-1.0.7.jar", version: "1.0.7", license: "BSD", url: "https://github.com/EsotericSoftware/reflectasm", licenseUrl: "http://opensource.org/licenses/BSD-3-Clause")
|
||||
libraryLicense(name: "Relax NG Object Model", libraryName: "rngom-20051226-patched.jar", license: "MIT", url: "http://java.net/projects/rngom/", licenseUrl: "http://www.opensource.org/licenses/mit-license.php")
|
||||
|
||||
@@ -56,9 +56,15 @@ public class SdkSettingsStep extends ModuleWizardStep {
|
||||
private final JPanel myJdkPanel;
|
||||
|
||||
public SdkSettingsStep(SettingsStep settingsStep, @NotNull ModuleBuilder moduleBuilder,
|
||||
@NotNull Condition<SdkTypeId> sdkFilter) {
|
||||
@NotNull Condition<SdkTypeId> sdkTypeIdFilter) {
|
||||
|
||||
this(settingsStep.getContext(), moduleBuilder, sdkFilter);
|
||||
this(settingsStep, moduleBuilder, sdkTypeIdFilter, null);
|
||||
}
|
||||
|
||||
public SdkSettingsStep(SettingsStep settingsStep, @NotNull ModuleBuilder moduleBuilder,
|
||||
@NotNull Condition<SdkTypeId> sdkTypeIdFilter, @Nullable Condition<Sdk> sdkFilter) {
|
||||
|
||||
this(settingsStep.getContext(), moduleBuilder, sdkTypeIdFilter, sdkFilter);
|
||||
if (!isEmpty()) {
|
||||
settingsStep.addSettingsField(getSdkFieldLabel(settingsStep.getContext().getProject()), myJdkPanel);
|
||||
}
|
||||
@@ -66,7 +72,8 @@ public class SdkSettingsStep extends ModuleWizardStep {
|
||||
|
||||
public SdkSettingsStep(WizardContext context,
|
||||
@NotNull ModuleBuilder moduleBuilder,
|
||||
@NotNull Condition<SdkTypeId> sdkFilter) {
|
||||
@NotNull Condition<SdkTypeId> sdkTypeIdFilter,
|
||||
@Nullable Condition<Sdk> sdkFilter) {
|
||||
myModuleBuilder = moduleBuilder;
|
||||
|
||||
myWizardContext = context;
|
||||
@@ -74,7 +81,11 @@ public class SdkSettingsStep extends ModuleWizardStep {
|
||||
Project project = myWizardContext.getProject();
|
||||
myModel.reset(project);
|
||||
|
||||
myJdkComboBox = new JdkComboBox(myModel, sdkFilter, sdkFilter, false);
|
||||
if (sdkFilter == null) {
|
||||
sdkFilter = JdkComboBox.getSdkFilter(sdkTypeIdFilter);
|
||||
}
|
||||
|
||||
myJdkComboBox = new JdkComboBox(myModel, sdkFilter, sdkTypeIdFilter, false);
|
||||
myJdkPanel = new JPanel(new GridBagLayout());
|
||||
|
||||
final PropertiesComponent component = project == null ? PropertiesComponent.getInstance() : PropertiesComponent.getInstance(project);
|
||||
@@ -91,7 +102,7 @@ public class SdkSettingsStep extends ModuleWizardStep {
|
||||
}
|
||||
});
|
||||
|
||||
Sdk sdk = getPreselectedSdk(project, component.getValue(selectedJdkProperty), sdkFilter);
|
||||
Sdk sdk = getPreselectedSdk(project, component.getValue(selectedJdkProperty), sdkTypeIdFilter);
|
||||
myJdkComboBox.setSelectedJdk(sdk);
|
||||
|
||||
JButton button = new JButton("Ne\u001Bw...");
|
||||
@@ -103,7 +114,7 @@ public class SdkSettingsStep extends ModuleWizardStep {
|
||||
myJdkPanel.add(myJdkComboBox, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, CENTER, HORIZONTAL, JBUI.emptyInsets(), 0, 0));
|
||||
myJdkPanel.add(myJdkComboBox.getSetUpButton(), new GridBagConstraints(1, 0, 1, 1, 0, 0, WEST, NONE, JBUI.insetsLeft(4), 0, 0));
|
||||
if (myJdkComboBox.getItemCount() == 0) {
|
||||
SdkType type = ContainerUtil.find(SdkType.getAllTypes(), sdkFilter);
|
||||
SdkType type = ContainerUtil.find(SdkType.getAllTypes(), sdkTypeIdFilter);
|
||||
if (type != null && type.getDownloadSdkUrl() != null) {
|
||||
HyperlinkLabel label = new HyperlinkLabel("Download " + type.getPresentableName());
|
||||
label.setHyperlinkTarget(type.getDownloadSdkUrl());
|
||||
|
||||
@@ -55,7 +55,7 @@ public class JdkComboBox extends ComboBoxWithWidePopup {
|
||||
private static final Icon EMPTY_ICON = EmptyIcon.create(1, 16);
|
||||
|
||||
@Nullable
|
||||
private final Condition<SdkTypeId> myFilter;
|
||||
private final Condition<Sdk> myFilter;
|
||||
@Nullable
|
||||
private final Condition<SdkTypeId> myCreationFilter;
|
||||
private JButton mySetUpButton;
|
||||
@@ -66,11 +66,11 @@ public class JdkComboBox extends ComboBoxWithWidePopup {
|
||||
|
||||
public JdkComboBox(@NotNull final ProjectSdksModel jdkModel,
|
||||
@Nullable Condition<SdkTypeId> filter) {
|
||||
this(jdkModel, filter, filter, false);
|
||||
this(jdkModel, getSdkFilter(filter), filter, false);
|
||||
}
|
||||
|
||||
public JdkComboBox(@NotNull final ProjectSdksModel jdkModel,
|
||||
@Nullable Condition<SdkTypeId> filter,
|
||||
@Nullable Condition<Sdk> filter,
|
||||
@Nullable Condition<SdkTypeId> creationFilter,
|
||||
boolean addSuggestedItems) {
|
||||
super(new JdkComboBoxModel(jdkModel, filter, addSuggestedItems));
|
||||
@@ -280,7 +280,7 @@ public class JdkComboBox extends ComboBoxWithWidePopup {
|
||||
final ProjectSdksModel projectJdksModel = ProjectStructureConfigurable.getInstance(project).getProjectJdksModel();
|
||||
List<Sdk> projectJdks = new ArrayList<Sdk>(projectJdksModel.getProjectSdks().values());
|
||||
if (myFilter != null) {
|
||||
projectJdks = ContainerUtil.filter(projectJdks, getSdkFilter(myFilter));
|
||||
projectJdks = ContainerUtil.filter(projectJdks, myFilter);
|
||||
}
|
||||
Collections.sort(projectJdks, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName()));
|
||||
for (Sdk projectJdk : projectJdks) {
|
||||
@@ -289,11 +289,11 @@ public class JdkComboBox extends ComboBoxWithWidePopup {
|
||||
}
|
||||
|
||||
private static class JdkComboBoxModel extends DefaultComboBoxModel {
|
||||
public JdkComboBoxModel(final ProjectSdksModel jdksModel, @Nullable Condition<SdkTypeId> sdkFilter, boolean addSuggested) {
|
||||
public JdkComboBoxModel(final ProjectSdksModel jdksModel, @Nullable Condition<Sdk> sdkFilter, boolean addSuggested) {
|
||||
Sdk[] jdks = jdksModel.getSdks();
|
||||
Arrays.sort(jdks, (s1, s2) -> s1.getName().compareToIgnoreCase(s2.getName()));
|
||||
for (Sdk jdk : jdks) {
|
||||
if (sdkFilter == null || sdkFilter.value(jdk.getSdkType())) {
|
||||
if (sdkFilter == null || sdkFilter.value(jdk)) {
|
||||
addElement(new JdkComboBoxItem(jdk));
|
||||
}
|
||||
}
|
||||
@@ -302,10 +302,10 @@ public class JdkComboBox extends ComboBoxWithWidePopup {
|
||||
}
|
||||
}
|
||||
|
||||
protected void addSuggestedItems(@Nullable Condition<SdkTypeId> sdkFilter, Sdk[] jdks) {
|
||||
protected void addSuggestedItems(@Nullable Condition<Sdk> sdkFilter, Sdk[] jdks) {
|
||||
SdkType[] types = SdkType.getAllTypes();
|
||||
for (SdkType type : types) {
|
||||
if (sdkFilter == null || sdkFilter.value(type) && ContainerUtil.find(jdks, sdk -> sdk.getSdkType() == type) == null) {
|
||||
if (sdkFilter == null || ContainerUtil.find(jdks, sdkFilter) == null) {
|
||||
String homePath = type.suggestHomePath();
|
||||
if (homePath != null && type.isValidSdkHome(homePath)) {
|
||||
addElement(new SuggestedJdkItem(type, homePath));
|
||||
@@ -321,7 +321,7 @@ public class JdkComboBox extends ComboBoxWithWidePopup {
|
||||
}
|
||||
}
|
||||
|
||||
private static Condition<Sdk> getSdkFilter(@Nullable final Condition<SdkTypeId> filter) {
|
||||
public static Condition<Sdk> getSdkFilter(@Nullable final Condition<SdkTypeId> filter) {
|
||||
return filter == null ? Conditions.<Sdk>alwaysTrue() : (Condition<Sdk>)sdk -> filter.value(sdk.getSdkType());
|
||||
}
|
||||
|
||||
|
||||
-6
@@ -406,12 +406,6 @@ class PostHighlightingVisitor {
|
||||
@NotNull PsiIdentifier identifier,
|
||||
@NotNull ProgressIndicator progress) {
|
||||
if (!myRefCountHolder.isReferenced(parameter) && !UnusedSymbolUtil.isImplicitUsage(myProject, parameter, progress)) {
|
||||
//parameter is defined by functional interface
|
||||
final PsiElement declarationScope = parameter.getDeclarationScope();
|
||||
if (declarationScope instanceof PsiMethod &&
|
||||
myRefCountHolder.isReferencedByMethodReference((PsiMethod)declarationScope, myLanguageLevel)) {
|
||||
return null;
|
||||
}
|
||||
String message = JavaErrorMessages.message("parameter.is.not.used", identifier.getText());
|
||||
return UnusedSymbolUtil.createUnusedSymbolInfo(identifier, message, myDeadCodeInfoType);
|
||||
}
|
||||
|
||||
-20
@@ -222,26 +222,6 @@ class RefCountHolder {
|
||||
return usedStatus == Boolean.TRUE;
|
||||
}
|
||||
|
||||
boolean isReferencedByMethodReference(@NotNull PsiMethod method, @NotNull LanguageLevel languageLevel) {
|
||||
if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) return false;
|
||||
|
||||
Collection<PsiReference> array;
|
||||
synchronized (myLocalRefsMap) {
|
||||
array = myLocalRefsMap.get(method);
|
||||
}
|
||||
|
||||
if (!array.isEmpty()) {
|
||||
for (PsiReference reference : array) {
|
||||
final PsiElement element = reference.getElement();
|
||||
if (element instanceof PsiMethodReferenceExpression) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isParameterUsedRecursively(@NotNull PsiElement element, @NotNull Collection<PsiReference> array) {
|
||||
if (!(element instanceof PsiParameter)) return false;
|
||||
PsiParameter parameter = (PsiParameter)element;
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.psi.stubsHierarchy.impl;
|
||||
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
|
||||
import com.intellij.util.BitUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@@ -69,7 +70,7 @@ public class StubResolver {
|
||||
private void findType(Symbol startScope, int name, Set<Symbol> symbols) throws IncompleteHierarchyException {
|
||||
// looking up
|
||||
for (Symbol s = startScope; s != null; s = s.myOwner)
|
||||
findMemberType(s, name, symbols, new HashSet<Symbol>());
|
||||
findMemberType(s, name, symbols);
|
||||
// type from current package
|
||||
findIdentInPackage(startScope.pkg(), name, IndexTree.CLASS, symbols);
|
||||
}
|
||||
@@ -79,7 +80,7 @@ public class StubResolver {
|
||||
if (receiver.isPackage())
|
||||
findIdentInPackage((Symbol.PackageSymbol)receiver, name, kind, symbols);
|
||||
else
|
||||
findMemberType(receiver, name, symbols, new HashSet<Symbol>());
|
||||
findMemberType(receiver, name, symbols);
|
||||
}
|
||||
|
||||
private void findIdentInPackage(Symbol.PackageSymbol pck, int name, int kind, Set<Symbol> symbols) {
|
||||
@@ -97,19 +98,34 @@ public class StubResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private void findMemberType(Symbol s, int name, Set<Symbol> symbols, Set<Symbol> processed) throws IncompleteHierarchyException {
|
||||
if (!processed.add(s)) {
|
||||
return;
|
||||
private void findMemberType(Symbol s, int name, Set<Symbol> symbols) throws IncompleteHierarchyException {
|
||||
if (s.isClass()) {
|
||||
processInheritedMembers((Symbol.ClassSymbol)s, name, false, symbols, null);
|
||||
} else {
|
||||
processMembers(s.getMembers(), name, symbols, false);
|
||||
}
|
||||
processMembers(s.getMembers(), name, symbols, false);
|
||||
if (s.isClass())
|
||||
findInheritedMemberType((Symbol.ClassSymbol)s, name, symbols, processed);
|
||||
}
|
||||
|
||||
private void findInheritedMemberType(Symbol.ClassSymbol c, int name, Set<Symbol> symbols, Set<Symbol> processed)
|
||||
throws IncompleteHierarchyException {
|
||||
for (Symbol.ClassSymbol st : c.getSuperClasses(myConnector))
|
||||
findMemberType(st, name, symbols, processed);
|
||||
private void processInheritedMembers(Symbol.ClassSymbol s,
|
||||
int name,
|
||||
boolean requireStatic,
|
||||
Set<Symbol> symbols,
|
||||
@Nullable Set<Symbol> processed) throws IncompleteHierarchyException {
|
||||
processMembers(s.getMembers(), name, symbols, requireStatic);
|
||||
|
||||
@CompactArray(Symbol.ClassSymbol.class) Object supers = s.getSuperClasses(myConnector);
|
||||
if (supers == null) return;
|
||||
|
||||
if (processed == null) processed = new HashSet<>();
|
||||
if (!processed.add(s)) return;
|
||||
|
||||
if (supers instanceof Symbol.ClassSymbol) {
|
||||
processInheritedMembers((Symbol.ClassSymbol)supers, name, requireStatic, symbols, processed);
|
||||
} else if (supers instanceof Symbol.ClassSymbol[]) {
|
||||
for (Symbol.ClassSymbol st : (Symbol.ClassSymbol[])supers) {
|
||||
processInheritedMembers(st, name, requireStatic, symbols, processed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Symbol.ClassSymbol[] loadClass(@NotNull QualifiedName fqn) {
|
||||
@@ -171,16 +187,7 @@ public class StubResolver {
|
||||
|
||||
// handling of import static `tsym.name` as
|
||||
private void importNamedStatic(final Symbol.ClassSymbol tsym, final int name, final Set<Symbol> symbols) throws IncompleteHierarchyException {
|
||||
new Object() {
|
||||
Set<Symbol> processed = new HashSet<Symbol>();
|
||||
void importFrom(Symbol.ClassSymbol cs) throws IncompleteHierarchyException {
|
||||
if (cs == null || !processed.add(cs))
|
||||
return;
|
||||
for (Symbol.ClassSymbol c : cs.getSuperClasses(myConnector))
|
||||
importFrom(c);
|
||||
processMembers(cs.getMembers(), name, symbols, true);
|
||||
}
|
||||
}.importFrom(tsym);
|
||||
processInheritedMembers(tsym, name, true, symbols, null);
|
||||
}
|
||||
|
||||
private static void processMembers(Symbol.ClassSymbol[] members, int name, Set<Symbol> symbols, boolean requireStatic) {
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
|
||||
import com.intellij.util.BitUtil;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -125,13 +126,14 @@ public abstract class Symbol {
|
||||
return BitUtil.isSet(myFlags, CONNECT_STARTED);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
ClassSymbol[] getSuperClasses(StubHierarchyConnector connector) throws IncompleteHierarchyException {
|
||||
@Nullable
|
||||
@CompactArray(ClassSymbol.class)
|
||||
Object getSuperClasses(StubHierarchyConnector connector) throws IncompleteHierarchyException {
|
||||
connect(connector);
|
||||
if (isHierarchyIncomplete()) {
|
||||
throw IncompleteHierarchyException.INSTANCE;
|
||||
}
|
||||
return rawSuperClasses();
|
||||
return mySuperClasses;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.TargetElementUtil;
|
||||
import com.intellij.codeInsight.highlighting.HighlightManager;
|
||||
import com.intellij.codeInsight.intention.QuickFixFactory;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
@@ -27,6 +28,7 @@ import com.intellij.openapi.editor.colors.EditorColors;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
@@ -77,38 +79,43 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
|
||||
|
||||
final String localName = local.getName();
|
||||
|
||||
final Query<PsiReference> query = ReferencesSearch.search(local, local.getUseScope());
|
||||
if (query.findFirst() == null){
|
||||
LOG.assertTrue(refExpr == null);
|
||||
String message = RefactoringBundle.message("variable.is.never.used", localName);
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.INLINE_VARIABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiClass containingClass = PsiTreeUtil.getParentOfType(local, PsiClass.class);
|
||||
final List<PsiElement> innerClassesWithUsages = Collections.synchronizedList(new ArrayList<PsiElement>());
|
||||
final List<PsiElement> innerClassUsages = Collections.synchronizedList(new ArrayList<PsiElement>());
|
||||
query.forEach(psiReference -> {
|
||||
final PsiElement element = psiReference.getElement();
|
||||
PsiElement innerClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, PsiLambdaExpression.class);
|
||||
while (innerClass != containingClass && innerClass != null) {
|
||||
final PsiClass parentPsiClass = PsiTreeUtil.getParentOfType(innerClass, PsiClass.class, true);
|
||||
if (parentPsiClass == containingClass) {
|
||||
if (innerClass instanceof PsiLambdaExpression) {
|
||||
if (PsiTreeUtil.isAncestor(innerClass, local, false)) {
|
||||
innerClassesWithUsages.add(element);
|
||||
innerClass = parentPsiClass;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
innerClassesWithUsages.add(innerClass);
|
||||
innerClassUsages.add(element);
|
||||
}
|
||||
innerClass = parentPsiClass;
|
||||
final PsiClass containingClass = PsiTreeUtil.getParentOfType(local, PsiClass.class);
|
||||
final Query<PsiReference> query = ReferencesSearch.search(local, local.getUseScope());
|
||||
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
|
||||
if (query.findFirst() == null){
|
||||
LOG.assertTrue(refExpr == null);
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
String message = RefactoringBundle.message("variable.is.never.used", localName);
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.INLINE_VARIABLE);
|
||||
}, ModalityState.NON_MODAL);
|
||||
return;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
query.forEach(psiReference -> {
|
||||
final PsiElement element = psiReference.getElement();
|
||||
PsiElement innerClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, PsiLambdaExpression.class);
|
||||
while (innerClass != containingClass && innerClass != null) {
|
||||
final PsiClass parentPsiClass = PsiTreeUtil.getParentOfType(innerClass, PsiClass.class, true);
|
||||
if (parentPsiClass == containingClass) {
|
||||
if (innerClass instanceof PsiLambdaExpression) {
|
||||
if (PsiTreeUtil.isAncestor(innerClass, local, false)) {
|
||||
innerClassesWithUsages.add(element);
|
||||
innerClass = parentPsiClass;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
innerClassesWithUsages.add(innerClass);
|
||||
innerClassUsages.add(element);
|
||||
}
|
||||
innerClass = parentPsiClass;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
}, "Find Usages", true, project)) {
|
||||
return;
|
||||
}
|
||||
final PsiCodeBlock containerBlock = PsiTreeUtil.getParentOfType(local, PsiCodeBlock.class);
|
||||
if (containerBlock == null) {
|
||||
final String message = RefactoringBundle.getCannotRefactorMessage("Variable is declared outside a code block");
|
||||
@@ -116,9 +123,7 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiExpression defToInline = innerClassesWithUsages.isEmpty()
|
||||
? getDefToInline(local, refExpr, containerBlock)
|
||||
: getDefToInline(local, innerClassesWithUsages.get(0), containerBlock);
|
||||
final PsiExpression defToInline = getDefToInline(local, innerClassesWithUsages.isEmpty() ? refExpr : innerClassesWithUsages.get(0), containerBlock);
|
||||
if (defToInline == null){
|
||||
final String key = refExpr == null ? "variable.has.no.initializer" : "variable.has.no.dominating.definition";
|
||||
String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message(key, localName));
|
||||
@@ -150,7 +155,7 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
|
||||
}
|
||||
|
||||
if (refExpr != null && inlineLocalDialog.isInlineThis()) {
|
||||
refsToInlineList = Collections.<PsiElement>singletonList(refExpr);
|
||||
refsToInlineList = Collections.singletonList(refExpr);
|
||||
inlineAll.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,11 +183,7 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps
|
||||
if (type instanceof PsiClassReferenceType) {
|
||||
return ((PsiClassReferenceType)type).getReference();
|
||||
}
|
||||
|
||||
final PsiClassType.ClassResolveResult resolveResult = type.resolveGenerics();
|
||||
final PsiClass refClass = resolveResult.getElement();
|
||||
assert refClass != null : type;
|
||||
return new LightClassReference(myManager, type.getCanonicalText(true), refClass, resolveResult.getSubstitutor());
|
||||
return new LightClassTypeReference(myManager, type);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -15,27 +15,21 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.light;
|
||||
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class LightClassReference extends LightElement implements PsiJavaCodeReferenceElement {
|
||||
private final String myText;
|
||||
public class LightClassReference extends LightClassReferenceBase implements PsiJavaCodeReferenceElement {
|
||||
|
||||
private final String myClassName;
|
||||
private final PsiElement myContext;
|
||||
@NotNull private final GlobalSearchScope myResolveScope;
|
||||
private final PsiClass myRefClass;
|
||||
private final PsiSubstitutor mySubstitutor;
|
||||
|
||||
private LightReferenceParameterList myParameterList;
|
||||
|
||||
private LightClassReference(@NotNull PsiManager manager,
|
||||
@NotNull @NonNls String text,
|
||||
@Nullable @NonNls String className,
|
||||
@@ -43,8 +37,7 @@ public class LightClassReference extends LightElement implements PsiJavaCodeRefe
|
||||
@NotNull GlobalSearchScope resolveScope,
|
||||
@Nullable PsiElement context,
|
||||
@Nullable PsiClass refClass) {
|
||||
super(manager, JavaLanguage.INSTANCE);
|
||||
myText = text;
|
||||
super(manager, text);
|
||||
myClassName = className;
|
||||
myResolveScope = resolveScope;
|
||||
|
||||
@@ -107,32 +100,6 @@ public class LightClassReference extends LightElement implements PsiJavaCodeRefe
|
||||
return new CandidateInfo(resolved, substitutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JavaResolveResult[] multiResolve(boolean incompleteCode){
|
||||
final JavaResolveResult result = advancedResolve(incompleteCode);
|
||||
if(result != JavaResolveResult.EMPTY) return new JavaResolveResult[]{result};
|
||||
return JavaResolveResult.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processVariants(@NotNull PsiScopeProcessor processor){
|
||||
throw new RuntimeException("Variants are not available for light references");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getReferenceNameElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiReferenceParameterList getParameterList() {
|
||||
if (myParameterList == null) {
|
||||
myParameterList = new LightReferenceParameterList(myManager, PsiTypeElement.EMPTY_ARRAY);
|
||||
}
|
||||
return myParameterList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQualifiedName() {
|
||||
if (myClassName != null) {
|
||||
@@ -162,36 +129,6 @@ public class LightClassReference extends LightElement implements PsiJavaCodeRefe
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return myText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiReference getReference() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getCanonicalText() {
|
||||
String name = getQualifiedName();
|
||||
if (name == null) return "";
|
||||
PsiType[] types = getTypeParameters();
|
||||
if (types.length == 0) return name;
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(name);
|
||||
buf.append('<');
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (i > 0) buf.append(',');
|
||||
buf.append(types[i].getCanonicalText());
|
||||
}
|
||||
buf.append('>');
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement copy() {
|
||||
if (myClassName != null) {
|
||||
@@ -207,79 +144,11 @@ public class LightClassReference extends LightElement implements PsiJavaCodeRefe
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
|
||||
//TODO?
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
|
||||
//TODO?
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof JavaElementVisitor) {
|
||||
((JavaElementVisitor)visitor).visitReferenceElement(this);
|
||||
}
|
||||
else {
|
||||
visitor.visitElement(this);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "LightClassReference:" + myText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReferenceTo(PsiElement element) {
|
||||
return element instanceof PsiClass && getManager().areElementsEquivalent(resolve(), element);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Object[] getVariants() {
|
||||
throw new RuntimeException("Variants are not available for light references");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSoft(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextRange getRangeInElement() {
|
||||
return new TextRange(0, getTextLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getElement() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return myRefClass == null || myRefClass.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public PsiType[] getTypeParameters() {
|
||||
return PsiType.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getQualifier() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQualified() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GlobalSearchScope getResolveScope() {
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.light;
|
||||
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
abstract class LightClassReferenceBase extends LightElement implements PsiJavaCodeReferenceElement {
|
||||
|
||||
protected final String myText;
|
||||
|
||||
private LightReferenceParameterList myParameterList;
|
||||
|
||||
protected LightClassReferenceBase(@NotNull PsiManager manager, @NotNull String text) {
|
||||
super(manager, JavaLanguage.INSTANCE);
|
||||
myText = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JavaResolveResult[] multiResolve(boolean incompleteCode) {
|
||||
final JavaResolveResult result = advancedResolve(incompleteCode);
|
||||
if (result != JavaResolveResult.EMPTY) return new JavaResolveResult[]{result};
|
||||
return JavaResolveResult.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processVariants(@NotNull PsiScopeProcessor processor) {
|
||||
throw new RuntimeException("Variants are not available for light references");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getReferenceNameElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiReferenceParameterList getParameterList() {
|
||||
if (myParameterList == null) {
|
||||
myParameterList = new LightReferenceParameterList(myManager, PsiTypeElement.EMPTY_ARRAY);
|
||||
}
|
||||
return myParameterList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQualifiedName() {
|
||||
PsiClass psiClass = (PsiClass)resolve();
|
||||
if (psiClass != null) {
|
||||
return psiClass.getQualifiedName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return myText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiReference getReference() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getCanonicalText() {
|
||||
String name = getQualifiedName();
|
||||
if (name == null) return "";
|
||||
PsiType[] types = getTypeParameters();
|
||||
if (types.length == 0) return name;
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(name);
|
||||
buf.append('<');
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (i > 0) buf.append(',');
|
||||
buf.append(types[i].getCanonicalText());
|
||||
}
|
||||
buf.append('>');
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
|
||||
//TODO?
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
|
||||
//TODO?
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof JavaElementVisitor) {
|
||||
((JavaElementVisitor)visitor).visitReferenceElement(this);
|
||||
}
|
||||
else {
|
||||
visitor.visitElement(this);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReferenceTo(PsiElement element) {
|
||||
return element instanceof PsiClass && getManager().areElementsEquivalent(resolve(), element);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Object[] getVariants() {
|
||||
throw new RuntimeException("Variants are not available for light references");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSoft() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextRange getRangeInElement() {
|
||||
return new TextRange(0, getTextLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getElement() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public PsiType[] getTypeParameters() {
|
||||
return PsiType.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getQualifier() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQualified() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.light;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class LightClassTypeReference extends LightClassReferenceBase implements PsiJavaCodeReferenceElement {
|
||||
|
||||
private final @NotNull PsiClassType myType;
|
||||
|
||||
private LightClassTypeReference(@NotNull PsiManager manager, @NotNull String text, @NotNull PsiClassType type) {
|
||||
super(manager, text);
|
||||
myType = type;
|
||||
}
|
||||
|
||||
public LightClassTypeReference(@NotNull PsiManager manager, @NotNull PsiClassType type) {
|
||||
this(manager, type.getCanonicalText(true), type);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement resolve() {
|
||||
return myType.resolve();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JavaResolveResult advancedResolve(boolean incompleteCode) {
|
||||
return myType.resolveGenerics();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getReferenceName() {
|
||||
return myType.getClassName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement copy() {
|
||||
return new LightClassTypeReference(myManager, myText, myType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return myType.isValid();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GlobalSearchScope getResolveScope() {
|
||||
return myType.getResolveScope();
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -20,6 +20,7 @@ import com.intellij.navigation.ColoredItemPresentation;
|
||||
import com.intellij.navigation.LocationPresentation;
|
||||
import com.intellij.openapi.editor.colors.CodeInsightColors;
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
import com.intellij.openapi.project.IndexNotReadyException;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
@@ -104,7 +105,12 @@ public abstract class JavaClassTreeElementBase<Value extends PsiElement> extends
|
||||
|
||||
@Override
|
||||
public TextAttributesKey getTextAttributesKey() {
|
||||
return isDeprecated() ? CodeInsightColors.DEPRECATED_ATTRIBUTES : null;
|
||||
try {
|
||||
return isDeprecated() ? CodeInsightColors.DEPRECATED_ATTRIBUTES : null;
|
||||
}
|
||||
catch (IndexNotReadyException ignore) {
|
||||
return null; // do not show deprecated elements while indexing
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDeprecated(){
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ class Test {
|
||||
|
||||
class Test2 {
|
||||
|
||||
static void m(Integer i) { }
|
||||
static void m(Integer <warning descr="Parameter 'i' is never used">i</warning>) { }
|
||||
|
||||
interface I1 {
|
||||
void m(int x);
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ abstract class AbstractCollection<E> implements Collection<E> {
|
||||
public boolean add(E e) {
|
||||
return true;
|
||||
}
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
public boolean addAll(Collection<? extends E> <warning descr="Parameter 'c' is never used">c</warning>) {
|
||||
boolean modified = false;
|
||||
return modified;
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,11 +6,11 @@ class Test {
|
||||
Test m(List<Integer> l1, List<Integer> l2);
|
||||
}
|
||||
|
||||
static Test meth(List<Integer>... lli) {
|
||||
static Test meth(List<Integer>... <warning descr="Parameter 'lli' is never used">lli</warning>) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Test(List<Integer>... lli) {}
|
||||
Test(List<Integer>... <warning descr="Parameter 'lli' is never used">lli</warning>) {}
|
||||
|
||||
{
|
||||
I <warning descr="Variable 'i1' is never used">i1</warning> = <warning descr="Unchecked generics array creation for varargs parameter">Test::meth</warning>;
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class A {
|
||||
private void test5(Integer i, String... strings) {}
|
||||
private void test5(Integer <warning descr="Parameter 'i' is never used">i</warning>, String... <warning descr="Parameter 'strings' is never used">strings</warning>) {}
|
||||
private void <warning descr="Private method 'test5(java.lang.Integer, java.lang.Integer, java.lang.String...)' is never used">test5</warning>(Integer i, Integer b, String... strings) {
|
||||
System.out.println(i);
|
||||
System.out.println(b);
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ class MyTest<T> {
|
||||
|
||||
public static class Builder<E> {
|
||||
|
||||
public Builder<E> add(E element) {
|
||||
public Builder<E> add(E <warning descr="Parameter 'element' is never used">element</warning>) {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -8,6 +8,6 @@ class Main {
|
||||
}
|
||||
|
||||
public static boolean checkForJdk(String <warning descr="Parameter 'homePath' is never used">homePath</warning>) {return false;}
|
||||
public static boolean checkForJdk(File homePath) {return false;}
|
||||
public static boolean checkForJdk(File <warning descr="Parameter 'homePath' is never used">homePath</warning>) {return false;}
|
||||
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -55,7 +55,7 @@ oromatcher.jar
|
||||
picocontainer.jar
|
||||
protobuf-2.5.0.jar
|
||||
proxy-vole_20131209.jar
|
||||
pty4j-0.7.jar
|
||||
pty4j-0.7.1.jar
|
||||
purejavacomm.jar
|
||||
resolver.jar
|
||||
rhino-js-1_7R4.jar
|
||||
|
||||
Binary file not shown.
@@ -32,13 +32,13 @@ public abstract class LookAheadLexer extends LexerBase{
|
||||
private final Queue<IElementType> myTypeCache;
|
||||
private final Queue<Integer> myEndOffsetCache;
|
||||
|
||||
public LookAheadLexer(final Lexer baseLexer, int capacity) {
|
||||
public LookAheadLexer(@NotNull Lexer baseLexer, int capacity) {
|
||||
myBaseLexer = baseLexer;
|
||||
myTypeCache = new Queue<IElementType>(capacity);
|
||||
myEndOffsetCache = new Queue<Integer>(capacity);
|
||||
}
|
||||
|
||||
public LookAheadLexer(final Lexer baseLexer) {
|
||||
public LookAheadLexer(@NotNull Lexer baseLexer) {
|
||||
this(baseLexer, 64);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public abstract class LookAheadLexer extends LexerBase{
|
||||
myEndOffsetCache.addLast(endOffset);
|
||||
}
|
||||
|
||||
protected void lookAhead(Lexer baseLexer) {
|
||||
protected void lookAhead(@NotNull Lexer baseLexer) {
|
||||
advanceLexer(baseLexer);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +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 org.jetbrains.concurrency;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface AsyncFunction<PARAM, RESULT> {
|
||||
@NotNull
|
||||
Promise<RESULT> fun(PARAM param);
|
||||
}
|
||||
@@ -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.
|
||||
@@ -203,7 +203,7 @@ public class AsyncPromise<T> extends Promise<T> implements Getter<T> {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public <SUB_RESULT> Promise<SUB_RESULT> thenAsync(@NotNull final AsyncFunction<? super T, SUB_RESULT> fulfilled) {
|
||||
public <SUB_RESULT> Promise<SUB_RESULT> thenAsync(@NotNull final Function<? super T, Promise<SUB_RESULT>> fulfilled) {
|
||||
switch (state) {
|
||||
case PENDING:
|
||||
break;
|
||||
|
||||
@@ -1,39 +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 org.jetbrains.concurrency;
|
||||
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
class CountDownConsumer<T> implements Consumer<T> {
|
||||
private volatile int countDown;
|
||||
private final AsyncPromise<T> promise;
|
||||
private final T totalResult;
|
||||
|
||||
public CountDownConsumer(int countDown, @NotNull AsyncPromise<T> promise, @Nullable T totalResult) {
|
||||
this.countDown = countDown;
|
||||
this.promise = promise;
|
||||
this.totalResult = totalResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(T t) {
|
||||
if (--countDown == 0) {
|
||||
promise.setResult(totalResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -68,7 +68,7 @@ class DonePromise<T> extends Promise<T> implements Getter<T> {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <SUB_RESULT> Promise<SUB_RESULT> thenAsync(@NotNull AsyncFunction<? super T, SUB_RESULT> done) {
|
||||
public <SUB_RESULT> Promise<SUB_RESULT> thenAsync(@NotNull Function<? super T, Promise<SUB_RESULT>> done) {
|
||||
return done.fun(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +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 org.jetbrains.concurrency;
|
||||
|
||||
public interface ObsolescentAsyncFunction<PARAM, RESULT> extends AsyncFunction<PARAM, RESULT>, Obsolescent {
|
||||
}
|
||||
@@ -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.
|
||||
@@ -28,7 +28,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class Promise<T> {
|
||||
public static final Promise<Void> DONE = new DonePromise<Void>(null);
|
||||
@@ -70,40 +69,6 @@ public abstract class Promise<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Promise<?> all(@NotNull Collection<Promise<?>> promises) {
|
||||
if (promises.size() == 1) {
|
||||
return promises instanceof List ? ((List<Promise<?>>)promises).get(0) : promises.iterator().next();
|
||||
}
|
||||
else {
|
||||
return all(promises, null);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> Promise<T> all(@NotNull Collection<Promise<?>> promises, @Nullable T totalResult) {
|
||||
if (promises.isEmpty()) {
|
||||
//noinspection unchecked
|
||||
return (Promise<T>)DONE;
|
||||
}
|
||||
|
||||
final AsyncPromise<T> totalPromise = new AsyncPromise<T>();
|
||||
Consumer done = new CountDownConsumer<T>(promises.size(), totalPromise, totalResult);
|
||||
Consumer<Throwable> rejected = new Consumer<Throwable>() {
|
||||
@Override
|
||||
public void consume(Throwable error) {
|
||||
totalPromise.setError(error);
|
||||
}
|
||||
};
|
||||
|
||||
for (Promise<?> promise : promises) {
|
||||
//noinspection unchecked
|
||||
promise.done(done);
|
||||
promise.rejected(rejected);
|
||||
}
|
||||
return totalPromise;
|
||||
}
|
||||
|
||||
public static <T> Promise<T> any(@NotNull final Collection<Promise<T>> promises, @NotNull final String totalError) {
|
||||
if (promises.isEmpty()) {
|
||||
//noinspection unchecked
|
||||
@@ -187,7 +152,7 @@ public abstract class Promise<T> {
|
||||
public abstract <SUB_RESULT> Promise<SUB_RESULT> then(@NotNull Function<? super T, ? extends SUB_RESULT> done);
|
||||
|
||||
@NotNull
|
||||
public abstract <SUB_RESULT> Promise<SUB_RESULT> thenAsync(@NotNull AsyncFunction<? super T, SUB_RESULT> done);
|
||||
public abstract <SUB_RESULT> Promise<SUB_RESULT> thenAsync(@NotNull Function<? super T, Promise<SUB_RESULT>> done);
|
||||
|
||||
@NotNull
|
||||
public abstract State getState();
|
||||
|
||||
@@ -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.
|
||||
@@ -63,7 +63,7 @@ class RejectedPromise<T> extends Promise<T> {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <SUB_RESULT> Promise<SUB_RESULT> thenAsync(@NotNull AsyncFunction<? super T, SUB_RESULT> done) {
|
||||
public <SUB_RESULT> Promise<SUB_RESULT> thenAsync(@NotNull Function<? super T, Promise<SUB_RESULT>> done) {
|
||||
//noinspection unchecked
|
||||
return (Promise<SUB_RESULT>)this;
|
||||
}
|
||||
|
||||
@@ -1153,7 +1153,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
childNode.putUserData(BlockSupport.TREE_DEPTH_LIMIT_EXCEEDED, Boolean.TRUE);
|
||||
}
|
||||
|
||||
assert rootNode.textMatches(myText) : rootNode.getElementType();
|
||||
assert rootNode.getTextLength() == myText.length() : rootNode.getElementType();
|
||||
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.source;
|
||||
|
||||
import com.intellij.concurrency.JobScheduler;
|
||||
import com.intellij.extapi.psi.StubBasedPsiElementBase;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.LowMemoryWatcher;
|
||||
import com.intellij.openapi.util.UserDataHolderEx;
|
||||
import com.intellij.psi.impl.source.tree.AstPath;
|
||||
import com.intellij.psi.impl.source.tree.CompositeElement;
|
||||
import com.intellij.reference.SoftReference;
|
||||
@@ -27,7 +30,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A weak cache for all instantiated stub-based PSI to allow {@link CompositeElement#getPsi()} return it when AST is reloaded.<p/>
|
||||
@@ -35,24 +37,22 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
class AstPathPsiMap {
|
||||
/**
|
||||
* Not using ConcurrentWeakValueMap because we need to clean them up as ASTs in thousands of files are created and gc-ed.
|
||||
* So we have a single shared reference queue {@link MyReference#ourQueue} for that.
|
||||
* Not using ConcurrentWeakValueMap because we need to clean each of them up separately, when ASTs in thousands of files are created and gc-ed.
|
||||
* So we have a per-project single shared reference queue {@link #myQueue} for that.
|
||||
* Otherwise the files end up retaining lots of maps with all-gc-ed stuff inside, but the maps are still very large.
|
||||
*/
|
||||
private final ConcurrentMap<AstPath, MyReference> myMap = ContainerUtil.newConcurrentMap();
|
||||
|
||||
static {
|
||||
JobScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// clean up AstPath objects when no PSI is accessed, e.g. after project closing
|
||||
processQueue();
|
||||
}
|
||||
}, 5, 5, TimeUnit.SECONDS);
|
||||
private static final Key<MyReferenceQueue> STUB_PSI_REFS = Key.create("STUB_PSI_REFS");
|
||||
private final MyReferenceQueue myQueue;
|
||||
|
||||
AstPathPsiMap(@NotNull Project project) {
|
||||
MyReferenceQueue queue = project.getUserData(STUB_PSI_REFS);
|
||||
myQueue = queue != null ? queue : ((UserDataHolderEx)project).putUserDataIfAbsent(STUB_PSI_REFS, new MyReferenceQueue());
|
||||
}
|
||||
|
||||
void invalidatePsi() {
|
||||
processQueue();
|
||||
myQueue.cleanupStaleReferences();
|
||||
for (MyReference reference : myMap.values()) {
|
||||
StubBasedPsiElementBase<?> psi = SoftReference.dereference(reference);
|
||||
if (psi != null) {
|
||||
@@ -63,7 +63,7 @@ class AstPathPsiMap {
|
||||
}
|
||||
|
||||
void switchToStrongRefs() {
|
||||
processQueue();
|
||||
myQueue.cleanupStaleReferences();
|
||||
for (MyReference reference : myMap.values()) {
|
||||
StubBasedPsiElementBase<?> psi = SoftReference.dereference(reference);
|
||||
if (psi != null) {
|
||||
@@ -82,30 +82,38 @@ class AstPathPsiMap {
|
||||
|
||||
@NotNull
|
||||
StubBasedPsiElementBase<?> cachePsi(@NotNull AstPath key, @NotNull StubBasedPsiElementBase psi) {
|
||||
processQueue();
|
||||
myMap.put(key, new MyReference(psi, key));
|
||||
myQueue.cleanupStaleReferences();
|
||||
myMap.put(key, new MyReference(psi, key, myQueue));
|
||||
psi.setSubstrateRef(key);
|
||||
return psi;
|
||||
}
|
||||
|
||||
private static void processQueue() {
|
||||
while (true) {
|
||||
MyReference reference = (MyReference)MyReference.ourQueue.poll();
|
||||
if (reference == null) break;
|
||||
|
||||
AstPath key = reference.pathRef;
|
||||
key.getContainingFile().getRefToPsi().myMap.remove(key, reference);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyReference extends WeakReference<StubBasedPsiElementBase<?>> {
|
||||
static final ReferenceQueue<StubBasedPsiElementBase<?>> ourQueue = new ReferenceQueue<StubBasedPsiElementBase<?>>();
|
||||
final AstPath pathRef;
|
||||
|
||||
MyReference(StubBasedPsiElementBase psi, AstPath ref) {
|
||||
super(psi, ourQueue);
|
||||
MyReference(StubBasedPsiElementBase psi, AstPath ref, ReferenceQueue<StubBasedPsiElementBase<?>> queue) {
|
||||
super(psi, queue);
|
||||
pathRef = ref;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyReferenceQueue extends ReferenceQueue<StubBasedPsiElementBase<?>> {
|
||||
@SuppressWarnings("unused") LowMemoryWatcher watcher = LowMemoryWatcher.register(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
cleanupStaleReferences();
|
||||
}
|
||||
});
|
||||
|
||||
void cleanupStaleReferences() {
|
||||
while (true) {
|
||||
MyReference reference = (MyReference)poll();
|
||||
if (reference == null) break;
|
||||
|
||||
AstPath key = reference.pathRef;
|
||||
key.getContainingFile().getRefToPsi().myMap.remove(key, reference);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
|
||||
private boolean myInvalidated;
|
||||
private volatile boolean myAstLoaded;
|
||||
private volatile boolean myUseStrongRefs;
|
||||
private AstPathPsiMap myRefToPsi = new AstPathPsiMap();
|
||||
private AstPathPsiMap myRefToPsi;
|
||||
private final ThreadLocal<FileElement> myFileElementBeingLoaded = new ThreadLocal<FileElement>();
|
||||
protected final PsiManagerEx myManager;
|
||||
private volatile Getter<FileElement> myTreeElementPointer; // SoftReference/WeakReference to ASTNode or a strong reference to a tree if the file is a DummyHolder
|
||||
@@ -87,6 +87,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
|
||||
protected PsiFileImpl(@NotNull FileViewProvider provider ) {
|
||||
myManager = (PsiManagerEx)provider.getManager();
|
||||
myViewProvider = provider;
|
||||
myRefToPsi = new AstPathPsiMap(getProject());
|
||||
}
|
||||
|
||||
public void setContentElementType(final IElementType contentElementType) {
|
||||
@@ -482,7 +483,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
|
||||
PsiFileImpl clone = BlockSupportImpl.getFileCopy(this, providerCopy);
|
||||
copyCopyableDataTo(clone);
|
||||
|
||||
clone.myRefToPsi = new AstPathPsiMap();
|
||||
clone.myRefToPsi = new AstPathPsiMap(getProject());
|
||||
if (getTreeElement() != null) {
|
||||
// not set by provider in clone
|
||||
final FileElement treeClone = (FileElement)calcTreeElement().clone();
|
||||
@@ -776,7 +777,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
|
||||
|
||||
protected PsiFileImpl cloneImpl(FileElement treeElementClone) {
|
||||
PsiFileImpl clone = (PsiFileImpl)super.clone();
|
||||
clone.myRefToPsi = new AstPathPsiMap();
|
||||
clone.myRefToPsi = new AstPathPsiMap(getProject());
|
||||
clone.setTreeElementPointer(treeElementClone); // should not use setTreeElement here because cloned file still have VirtualFile (SCR17963)
|
||||
treeElementClone.setPsi(clone);
|
||||
return clone;
|
||||
|
||||
+3
-2
@@ -38,8 +38,9 @@ public class PsiMultiReference implements PsiPolyVariantReference {
|
||||
public static final Comparator<PsiReference> COMPARATOR = new Comparator<PsiReference>() {
|
||||
@Override
|
||||
public int compare(final PsiReference ref1, final PsiReference ref2) {
|
||||
if (ref1.isSoft() && !ref2.isSoft()) return 1;
|
||||
if (!ref1.isSoft() && ref2.isSoft()) return -1;
|
||||
boolean soft1 = ref1.isSoft();
|
||||
boolean soft2 = ref2.isSoft();
|
||||
if (soft1 != soft2) return soft1 ? 1 : -1;
|
||||
|
||||
boolean resolves1 = resolves(ref1);
|
||||
boolean resolves2 = resolves(ref2);
|
||||
|
||||
@@ -210,7 +210,7 @@ public class LazyParseableElement extends CompositeElement {
|
||||
|
||||
AstPath.cacheNodePaths(this);
|
||||
|
||||
assert super.textMatches(text) : "Text mismatch in " + getElementType();
|
||||
assertTextLengthIntact(text.length());
|
||||
myText = new SoftReference<CharSequence>(text);
|
||||
}
|
||||
}
|
||||
@@ -219,6 +219,14 @@ public class LazyParseableElement extends CompositeElement {
|
||||
}
|
||||
}
|
||||
|
||||
private void assertTextLengthIntact(int expected) {
|
||||
int length = 0;
|
||||
for (ASTNode node : getChildren(null)) {
|
||||
length += node.getTextLength();
|
||||
}
|
||||
assert length == expected : "Text mismatch in " + getElementType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rawAddChildrenWithoutNotifications(@NotNull TreeElement first) {
|
||||
if (!isParsed()) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypeRegistry;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.indexing.*;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
@@ -38,11 +39,6 @@ import java.util.Map;
|
||||
public class FileTypeIndex extends ScalarIndexExtension<FileType>
|
||||
implements FileBasedIndex.InputFilter, KeyDescriptor<FileType>, DataIndexer<FileType, Void, FileContent> {
|
||||
|
||||
@NotNull
|
||||
public static Collection<VirtualFile> getFiles(@NotNull FileType fileType, @NotNull GlobalSearchScope scope) {
|
||||
return FileBasedIndex.getInstance().getContainingFiles(NAME, fileType, scope);
|
||||
}
|
||||
|
||||
public static final ID<FileType, Void> NAME = ID.create("filetypes");
|
||||
|
||||
private final FileTypeRegistry myFileTypeManager;
|
||||
@@ -130,11 +126,24 @@ public class FileTypeIndex extends ScalarIndexExtension<FileType>
|
||||
}
|
||||
|
||||
public static boolean containsFileOfType(@NotNull FileType type, @NotNull GlobalSearchScope scope) {
|
||||
return !FileBasedIndex.getInstance().processValues(NAME, type, null, new FileBasedIndex.ValueProcessor<Void>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile file, Void value) {
|
||||
return false;
|
||||
}
|
||||
}, scope);
|
||||
return !processFiles(type, file -> false, scope);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Collection<VirtualFile> getFiles(@NotNull FileType fileType, @NotNull GlobalSearchScope scope) {
|
||||
return FileBasedIndex.getInstance().getContainingFiles(NAME, fileType, scope);
|
||||
}
|
||||
|
||||
public static boolean processFiles(@NotNull FileType fileType, @NotNull Processor<VirtualFile> processor, GlobalSearchScope scope) {
|
||||
return FileBasedIndex.getInstance().processValues(
|
||||
NAME,
|
||||
fileType,
|
||||
null,
|
||||
new FileBasedIndex.ValueProcessor<Void>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile file, Void value) {
|
||||
return processor.process(file);
|
||||
}
|
||||
}, scope);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +195,10 @@ public class FilenameIndex extends ScalarIndexExtension<String> {
|
||||
return result.toArray(new PsiFile[result.size()]);
|
||||
}
|
||||
|
||||
public static void processAllFileNames(@NotNull Processor<String> processor, @NotNull GlobalSearchScope scope, @NotNull IdFilter filter) {
|
||||
FileBasedIndex.getInstance().processAllKeys(NAME, processor, scope, filter);
|
||||
}
|
||||
|
||||
private static class MyDataIndexer implements DataIndexer<String, Void, FileContent> {
|
||||
@Override
|
||||
@NotNull
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.application.options.colors;
|
||||
|
||||
import com.intellij.application.options.EditorFontsConstants;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.IdeTooltipManager;
|
||||
import com.intellij.ide.ui.AntialiasingType;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.openapi.application.ApplicationBundle;
|
||||
@@ -27,10 +28,7 @@ import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.editor.colors.FontPreferences;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.FontComboBox;
|
||||
import com.intellij.ui.FontInfoRenderer;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
@@ -105,7 +103,11 @@ public class FontOptions extends JPanel implements OptionsPanel{
|
||||
myEnableLigaturesCheckbox.setBorder(null);
|
||||
panel.add(myEnableLigaturesCheckbox);
|
||||
JLabel warningIcon = new JLabel(AllIcons.General.BalloonWarning);
|
||||
warningIcon.setToolTipText(ApplicationBundle.message("ligatures.jre.warning", ApplicationNamesInfo.getInstance().getFullProductName()));
|
||||
IdeTooltipManager.getInstance().setCustomTooltip(
|
||||
warningIcon,
|
||||
new TooltipWithClickableLinks.ForBrowser(warningIcon,
|
||||
ApplicationBundle.message("ligatures.jre.warning",
|
||||
ApplicationNamesInfo.getInstance().getFullProductName())));
|
||||
warningIcon.setBorder(JBUI.Borders.emptyLeft(5));
|
||||
updateWarningIconVisibility(warningIcon);
|
||||
panel.add(warningIcon);
|
||||
|
||||
+3
@@ -144,6 +144,9 @@ public class PsiElementListNavigator {
|
||||
}).
|
||||
setCancelCallback(() -> {
|
||||
HintUpdateSupply.hideHint(list);
|
||||
if (listUpdaterTask != null) {
|
||||
return listUpdaterTask.cancelTask();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
final Ref<UsageView> usageView = new Ref<UsageView>();
|
||||
|
||||
+7
-16
@@ -300,7 +300,9 @@ public class ShowImplementationsAction extends AnAction implements PopupAction {
|
||||
})
|
||||
.setCancelCallback(() -> {
|
||||
ImplementationsUpdaterTask task = SoftReference.dereference(myTaskRef);
|
||||
cancelTask(task);
|
||||
if (task != null) {
|
||||
task.cancelTask();
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
})
|
||||
.createPopup();
|
||||
@@ -314,17 +316,6 @@ public class ShowImplementationsAction extends AnAction implements PopupAction {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean cancelTask(@Nullable ImplementationsUpdaterTask task) {
|
||||
if (task != null) {
|
||||
ProgressIndicator indicator = task.myIndicator;
|
||||
if (indicator != null) {
|
||||
indicator.cancel();
|
||||
}
|
||||
return task.setCanceled();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updateInBackground(Editor editor,
|
||||
@Nullable PsiElement element,
|
||||
@NotNull ImplementationViewComponent component,
|
||||
@@ -332,7 +323,9 @@ public class ShowImplementationsAction extends AnAction implements PopupAction {
|
||||
@NotNull AbstractPopup popup,
|
||||
@NotNull Ref<UsageView> usageView) {
|
||||
final ImplementationsUpdaterTask updaterTask = SoftReference.dereference(myTaskRef);
|
||||
cancelTask(updaterTask);
|
||||
if (updaterTask != null) {
|
||||
updaterTask.cancelTask();
|
||||
}
|
||||
|
||||
if (element == null) return; //already found
|
||||
final ImplementationsUpdaterTask task = new ImplementationsUpdaterTask(element, editor, title, isIncludeAlwaysSelf());
|
||||
@@ -412,7 +405,6 @@ public class ShowImplementationsAction extends AnAction implements PopupAction {
|
||||
private final PsiElement myElement;
|
||||
private final boolean myIncludeSelf;
|
||||
private PsiElement[] myElements;
|
||||
private volatile ProgressIndicator myIndicator;
|
||||
|
||||
private ImplementationsUpdaterTask(@NotNull PsiElement element, final Editor editor, final String caption, boolean includeSelf) {
|
||||
super(element.getProject(), ImplementationSearcher.SEARCHING_FOR_IMPLEMENTATIONS);
|
||||
@@ -445,7 +437,6 @@ public class ShowImplementationsAction extends AnAction implements PopupAction {
|
||||
|
||||
@Override
|
||||
public void run(@NotNull final ProgressIndicator indicator) {
|
||||
myIndicator = indicator;
|
||||
super.run(indicator);
|
||||
final ImplementationSearcher.BackgroundableImplementationSearcher implementationSearcher =
|
||||
new ImplementationSearcher.BackgroundableImplementationSearcher() {
|
||||
@@ -477,7 +468,7 @@ public class ShowImplementationsAction extends AnAction implements PopupAction {
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
if (!cancelTask(this)) {
|
||||
if (!cancelTask()) {
|
||||
myComponent.update(myElements, myComponent.getIndex());
|
||||
}
|
||||
super.onSuccess();
|
||||
|
||||
@@ -52,6 +52,7 @@ public abstract class BackgroundUpdaterTask<T> extends Task.Backgroundable {
|
||||
|
||||
private volatile boolean myCanceled;
|
||||
private volatile boolean myFinished;
|
||||
private volatile ProgressIndicator myIndicator;
|
||||
|
||||
public BackgroundUpdaterTask(Project project, String title, boolean canBeCancelled) {
|
||||
super(project, title, canBeCancelled);
|
||||
@@ -132,6 +133,7 @@ public abstract class BackgroundUpdaterTask<T> extends Task.Backgroundable {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
paintBusy(true);
|
||||
myIndicator = indicator;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,4 +150,12 @@ public abstract class BackgroundUpdaterTask<T> extends Task.Backgroundable {
|
||||
public boolean isFinished() {
|
||||
return myFinished;
|
||||
}
|
||||
|
||||
public boolean cancelTask() {
|
||||
ProgressIndicator indicator = myIndicator;
|
||||
if (indicator != null) {
|
||||
indicator.cancel();
|
||||
}
|
||||
return setCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +182,10 @@ public abstract class GotoTargetHandler implements CodeInsightActionHandler {
|
||||
setMovable(true).
|
||||
setCancelCallback(() -> {
|
||||
HintUpdateSupply.hideHint(list);
|
||||
final ListBackgroundUpdaterTask task = gotoData.listUpdaterTask;
|
||||
if (task != null) {
|
||||
return task.cancelTask();
|
||||
}
|
||||
return true;
|
||||
}).
|
||||
setCouldPin(popup1 -> {
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.intellij.ide.util.gotoByName.GotoActionModel;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.ex.ActionUtil;
|
||||
import com.intellij.openapi.actionSystem.impl.ActionMenu;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.TransactionGuard;
|
||||
@@ -53,10 +54,7 @@ import javax.swing.*;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import java.awt.*;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.*;
|
||||
import java.util.Set;
|
||||
|
||||
public class GotoActionAction extends GotoActionBase implements DumbAware {
|
||||
@@ -110,6 +108,9 @@ public class GotoActionAction extends GotoActionBase implements DumbAware {
|
||||
if (text != null && myDropdownPopup != null) {
|
||||
myDropdownPopup.setAdText(text, SwingConstants.LEFT);
|
||||
}
|
||||
|
||||
String description = getValueDescription(value);
|
||||
ActionMenu.showDescriptionInStatusBar(true, myList, description);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -124,6 +125,28 @@ public class GotoActionAction extends GotoActionBase implements DumbAware {
|
||||
return getAdText();
|
||||
}
|
||||
});
|
||||
myList.addMouseMotionListener(new MouseMotionAdapter() {
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
int index = myList.locationToIndex(e.getPoint());
|
||||
if (index == -1) return;
|
||||
Object value = myList.getModel().getElementAt(index);
|
||||
String description = getValueDescription(value);
|
||||
ActionMenu.showDescriptionInStatusBar(true, myList, description);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getValueDescription(@Nullable Object value) {
|
||||
if (value instanceof GotoActionModel.MatchedValue) {
|
||||
GotoActionModel.MatchedValue mv = (GotoActionModel.MatchedValue)value;
|
||||
if (mv.value instanceof GotoActionModel.ActionWrapper) {
|
||||
AnAction action = ((GotoActionModel.ActionWrapper)mv.value).getAction();
|
||||
return action.getTemplatePresentation().getDescription();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -144,7 +167,9 @@ public class GotoActionAction extends GotoActionBase implements DumbAware {
|
||||
public void setDisposed(boolean disposedFlag) {
|
||||
super.setDisposed(disposedFlag);
|
||||
Disposer.dispose(disposable);
|
||||
|
||||
|
||||
ActionMenu.showDescriptionInStatusBar(true, myList, null);
|
||||
|
||||
for (ListSelectionListener listener : myList.getListSelectionListeners()) {
|
||||
myList.removeListSelectionListener(listener);
|
||||
}
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ public class DefaultFileNavigationContributor implements ChooseByNameContributor
|
||||
@Override
|
||||
public void processNames(@NotNull final Processor<String> processor, @NotNull GlobalSearchScope scope, IdFilter filter) {
|
||||
long started = System.currentTimeMillis();
|
||||
FileBasedIndex.getInstance().processAllKeys(FilenameIndex.NAME, s -> processor.process(s), scope, filter);
|
||||
FilenameIndex.processAllFileNames(processor, scope, filter);
|
||||
if (IdFilter.LOG.isDebugEnabled()) {
|
||||
IdFilter.LOG.debug("All names retrieved:" + (System.currentTimeMillis() - started));
|
||||
}
|
||||
|
||||
@@ -541,6 +541,7 @@ public class GotoActionModel implements ChooseByNameModel, Comparator<Object>, E
|
||||
panel.add(createIconLabel(presentation.getIcon()), BorderLayout.WEST);
|
||||
}
|
||||
appendWithColoredMatches(nameComponent, getName(presentation.getText(), groupName, toggle), pattern, fg, isSelected);
|
||||
panel.setToolTipText(presentation.getDescription());
|
||||
|
||||
Shortcut[] shortcuts = KeymapManager.getInstance().getActiveKeymap().getShortcuts(ActionManager.getInstance().getId(anAction));
|
||||
String shortcutText = KeymapUtil.getPreferredShortcutText(
|
||||
|
||||
@@ -22,11 +22,14 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.SingleRootFileViewProvider;
|
||||
import com.intellij.psi.impl.PsiManagerEx;
|
||||
import com.intellij.psi.impl.file.impl.FileManager;
|
||||
import com.intellij.util.containers.WeakFactoryMap;
|
||||
import com.intellij.util.containers.ConcurrentWeakFactoryMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
@@ -35,7 +38,12 @@ public class MockFileManager implements FileManager {
|
||||
private final PsiManagerEx myManager;
|
||||
// in mock tests it's LightVirtualFile, they're only alive when they're referenced,
|
||||
// and there can not be several instances representing the same file
|
||||
private final WeakFactoryMap<VirtualFile, FileViewProvider> myViewProviders = new WeakFactoryMap<VirtualFile, FileViewProvider>() {
|
||||
private final FactoryMap<VirtualFile, FileViewProvider> myViewProviders = new ConcurrentWeakFactoryMap<VirtualFile, FileViewProvider>() {
|
||||
@Override
|
||||
protected Map<VirtualFile, FileViewProvider> createMap() {
|
||||
return ContainerUtil.createConcurrentWeakKeyWeakValueMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FileViewProvider create(VirtualFile key) {
|
||||
return new SingleRootFileViewProvider(myManager, key);
|
||||
|
||||
@@ -22,13 +22,11 @@ import com.intellij.internal.statistic.beans.UsageDescriptor;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.search.FileTypeIndex;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.NotNullFunction;
|
||||
import com.intellij.util.ThreeState;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.indexing.FileBasedIndex;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -64,21 +62,14 @@ public class FileTypeUsagesCollector extends AbstractApplicationUsagesCollector
|
||||
}
|
||||
final String ideaDirPath = getIdeaDirPath(project);
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
FileBasedIndex.getInstance().processValues(
|
||||
FileTypeIndex.NAME,
|
||||
fileType,
|
||||
null,
|
||||
new FileBasedIndex.ValueProcessor<Void>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile file, Void value) {
|
||||
//skip files from .idea directory otherwise 99% of projects would have XML and PLAIN_TEXT file types
|
||||
if (ideaDirPath == null || FileUtil.isAncestorThreeState(ideaDirPath, file.getPath(), true) == ThreeState.NO) {
|
||||
usedFileTypes.add(fileType);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}, GlobalSearchScope.projectScope(project));
|
||||
FileTypeIndex.processFiles(fileType, file -> {
|
||||
//skip files from .idea directory otherwise 99% of projects would have XML and PLAIN_TEXT file types
|
||||
if (ideaDirPath == null || FileUtil.isAncestorThreeState(ideaDirPath, file.getPath(), true) == ThreeState.NO) {
|
||||
usedFileTypes.add(fileType);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, GlobalSearchScope.projectScope(project));
|
||||
});
|
||||
}
|
||||
return ContainerUtil.map2Set(usedFileTypes, (NotNullFunction<FileType, UsageDescriptor>)fileType -> new UsageDescriptor(fileType.getName(), 1));
|
||||
|
||||
+2
-3
@@ -86,8 +86,7 @@ public abstract class LevelChooserAction extends ComboBoxAction implements DumbA
|
||||
return getSeverities(severityRegistrar, true);
|
||||
}
|
||||
|
||||
public static List<HighlightSeverity> getSeverities(final SeverityRegistrar severityRegistrar,
|
||||
boolean includeDoNotShow) {
|
||||
public static List<HighlightSeverity> getSeverities(final SeverityRegistrar severityRegistrar, boolean includeDoNotShow) {
|
||||
final List<HighlightSeverity> severities = new ArrayList<HighlightSeverity>();
|
||||
for (final SeverityRegistrar.SeverityBasedTextAttributes type : SeverityUtil.getRegisteredHighlightingInfoTypes(severityRegistrar)) {
|
||||
severities.add(type.getSeverity());
|
||||
@@ -95,7 +94,7 @@ public abstract class LevelChooserAction extends ComboBoxAction implements DumbA
|
||||
if (includeDoNotShow) {
|
||||
severities.add(HighlightSeverity.INFORMATION);
|
||||
}
|
||||
Collections.sort(severities, (a, b) -> -severityRegistrar.compare(a, b));
|
||||
Collections.sort(severities, severityRegistrar.reversed());
|
||||
return severities;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -270,7 +270,7 @@ public class CopyFilesOrDirectoriesDialog extends DialogWrapper {
|
||||
return;
|
||||
}
|
||||
|
||||
if (myFileCopy) {
|
||||
if (myFileCopy && myTargetDirectory != null) {
|
||||
if (FileTypeChooser.getKnownFileTypeOrAssociate(myTargetDirectory.getVirtualFile(), newName, myProject) == null) {
|
||||
myUnknownFileType = true;
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ import com.intellij.openapi.editor.colors.EditorFontType;
|
||||
import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
|
||||
import com.intellij.openapi.editor.markup.RangeHighlighter;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.progress.PerformInBackgroundOption;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.*;
|
||||
import com.intellij.openapi.vcs.actions.ActiveAnnotationGutter;
|
||||
@@ -47,10 +47,14 @@ import com.intellij.openapi.vcs.history.VcsHistorySession;
|
||||
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.text.DateFormatUtil;
|
||||
import com.intellij.util.ui.update.MergingUpdateQueue;
|
||||
import com.intellij.util.ui.update.Update;
|
||||
import com.intellij.vcs.history.VcsHistoryProviderEx;
|
||||
import com.intellij.vcsUtil.VcsUtil;
|
||||
import com.intellij.xml.util.XmlStringUtil;
|
||||
import org.jetbrains.annotations.CalledInAwt;
|
||||
import org.jetbrains.annotations.CalledWithReadLock;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -59,18 +63,13 @@ import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public class AnnotateStackTraceAction extends AnAction implements DumbAware {
|
||||
public class AnnotateStackTraceAction extends DumbAwareAction {
|
||||
private static final Logger LOG = Logger.getInstance(AnnotateStackTraceAction.class);
|
||||
|
||||
private final EditorHyperlinkSupport myHyperlinks;
|
||||
private Map<Integer, LastRevision> cache;
|
||||
private Date newestDate;
|
||||
private int maxDateLength = 0;
|
||||
private final Editor myEditor;
|
||||
private boolean myGutterShowed = false;
|
||||
|
||||
private boolean myIsLoading = false;
|
||||
|
||||
public AnnotateStackTraceAction(@NotNull Editor editor, @NotNull EditorHyperlinkSupport hyperlinks) {
|
||||
super("Show files modification info", null, AllIcons.Actions.Annotate);
|
||||
@@ -78,101 +77,37 @@ public class AnnotateStackTraceAction extends AnAction implements DumbAware {
|
||||
myEditor = editor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
boolean isShown = myEditor.getGutter().isAnnotationsShown();
|
||||
e.getPresentation().setEnabled(!isShown && !myIsLoading);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
cache = new HashMap<Integer, LastRevision>();
|
||||
myIsLoading = true;
|
||||
|
||||
ProgressManager.getInstance().run(new Task.Backgroundable(myEditor.getProject(), "Getting File History", true) {
|
||||
private final Object LOCK = new Object();
|
||||
private final MergingUpdateQueue myUpdateQueue = new MergingUpdateQueue("AnnotateStackTraceAction", 200, true, null);
|
||||
|
||||
private MyActiveAnnotationGutter myGutter;
|
||||
|
||||
ProgressManager.getInstance().run(
|
||||
new Task.Backgroundable(myEditor.getProject(), "Getting File History", true, PerformInBackgroundOption.ALWAYS_BACKGROUND) {
|
||||
@Override
|
||||
public boolean shouldStartInBackground() {
|
||||
return true;
|
||||
public void onCancel() {
|
||||
myEditor.getGutter().closeAllAnnotations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
}
|
||||
|
||||
private void showGutter() {
|
||||
ActiveAnnotationGutter gutter = new ActiveAnnotationGutter() {
|
||||
@Override
|
||||
public void doAction(int lineNum) {
|
||||
final LastRevision revision = cache.get(lineNum);
|
||||
if (revision == null) return;
|
||||
|
||||
VirtualFile file = getHyperlinkVirtualFile(myHyperlinks.findAllHyperlinksOnLine(lineNum));
|
||||
if (file == null) return;
|
||||
|
||||
final Project project = getProject();
|
||||
final AbstractVcs vcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(file);
|
||||
if (vcs != null) {
|
||||
final VcsRevisionNumber number = revision.getNumber();
|
||||
final VcsKey vcsKey = vcs.getKeyInstanceMethod();
|
||||
ShowAllAffectedGenericAction.showSubmittedFiles(project, number, file, vcsKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor getCursor(int lineNum) {
|
||||
return cache.containsKey(lineNum) ? Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) : Cursor.getDefaultCursor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLineText(int line, Editor editor) {
|
||||
final LastRevision revision = cache.get(line);
|
||||
if (revision != null) {
|
||||
return String.format("%"+maxDateLength+"s", DateFormatUtil.formatPrettyDate(revision.getDate())) + " " + revision.getAuthor();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTip(int line, Editor editor) {
|
||||
final LastRevision revision = cache.get(line);
|
||||
if (revision != null) {
|
||||
return XmlStringUtil.escapeString(
|
||||
revision.getAuthor() + " " + DateFormatUtil.formatDateTime(revision.getDate()) + "\n" +
|
||||
revision.getMessage()
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EditorFontType getStyle(int line, Editor editor) {
|
||||
LastRevision revision = cache.get(line);
|
||||
return revision != null && revision.getDate().equals(newestDate) ? EditorFontType.BOLD : EditorFontType.PLAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorKey getColor(int line, Editor editor) {
|
||||
return AnnotationSource.LOCAL.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getBgColor(int line, Editor editor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AnAction> getPopupActions(int line, Editor editor) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gutterClosed() {
|
||||
myGutterShowed = false;
|
||||
}
|
||||
};
|
||||
myEditor.getGutter().registerTextAnnotation(gutter, gutter);
|
||||
|
||||
myGutterShowed = true;
|
||||
public void onFinished() {
|
||||
myIsLoading = false;
|
||||
Disposer.dispose(myUpdateQueue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(@NotNull final ProgressIndicator indicator) {
|
||||
final List<VirtualFile> files = new ArrayList<VirtualFile>();
|
||||
final HashMap<VirtualFile, List<Integer>> files2lines = new HashMap<VirtualFile, List<Integer>>();
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
MultiMap<VirtualFile, Integer> files2lines = new MultiMap<>();
|
||||
Map<Integer, LastRevision> revisions = ContainerUtil.newHashMap();
|
||||
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
for (int line = 0; line < myEditor.getDocument().getLineCount(); line++) {
|
||||
@@ -180,52 +115,58 @@ public class AnnotateStackTraceAction extends AnAction implements DumbAware {
|
||||
VirtualFile file = getHyperlinkVirtualFile(myHyperlinks.findAllHyperlinksOnLine(line));
|
||||
if (file == null) continue;
|
||||
|
||||
if (files2lines.containsKey(file)) {
|
||||
files2lines.get(file).add(line);
|
||||
}
|
||||
else {
|
||||
final ArrayList<Integer> lines = new ArrayList<Integer>();
|
||||
lines.add(line);
|
||||
files2lines.put(file, lines);
|
||||
files.add(file);
|
||||
}
|
||||
files2lines.putValue(file, line);
|
||||
}
|
||||
});
|
||||
|
||||
for (VirtualFile file : files) {
|
||||
files2lines.entrySet().forEach(entry -> {
|
||||
indicator.checkCanceled();
|
||||
VirtualFile file = entry.getKey();
|
||||
Collection<Integer> lines = entry.getValue();
|
||||
|
||||
LastRevision revision = getLastRevision(file);
|
||||
if (revision != null) {
|
||||
final List<Integer> lines = files2lines.get(file);
|
||||
if (revision == null) return;
|
||||
|
||||
final Date date = revision.getDate();
|
||||
if (newestDate == null || date.after(newestDate)) {
|
||||
newestDate = date;
|
||||
}
|
||||
final int length = DateFormatUtil.formatPrettyDate(date).length();
|
||||
if (length > maxDateLength) {
|
||||
maxDateLength = length;
|
||||
}
|
||||
synchronized (LOCK) {
|
||||
for (Integer line : lines) {
|
||||
cache.put(line, revision);
|
||||
revisions.put(line, revision);
|
||||
}
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
if (!myGutterShowed) {
|
||||
showGutter();
|
||||
}
|
||||
else {
|
||||
((EditorGutterComponentEx)myEditor.getGutter()).revalidateMarkup();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
myUpdateQueue.queue(new Update("update") {
|
||||
@Override
|
||||
public void run() {
|
||||
updateGutter(indicator, revisions);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// myUpdateQueue can be disposed before the last revisions are passed to the gutter
|
||||
ApplicationManager.getApplication().invokeLater(() -> updateGutter(indicator, revisions));
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
private void updateGutter(@NotNull ProgressIndicator indicator, @NotNull Map<Integer, LastRevision> revisions) {
|
||||
if (indicator.isCanceled()) return;
|
||||
|
||||
if (myGutter == null) {
|
||||
myGutter = new MyActiveAnnotationGutter(getProject(), myHyperlinks, indicator);
|
||||
myEditor.getGutter().registerTextAnnotation(myGutter, myGutter);
|
||||
}
|
||||
|
||||
Map<Integer, LastRevision> revisionsCopy;
|
||||
synchronized (LOCK) {
|
||||
revisionsCopy = ContainerUtil.newHashMap(revisions);
|
||||
}
|
||||
|
||||
myGutter.updateData(revisionsCopy);
|
||||
((EditorGutterComponentEx)myEditor.getGutter()).revalidateMarkup();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LastRevision getLastRevision(@NotNull VirtualFile file) {
|
||||
try {
|
||||
final AbstractVcs vcs = VcsUtil.getVcsFor(myEditor.getProject(), file);
|
||||
AbstractVcs vcs = VcsUtil.getVcsFor(myEditor.getProject(), file);
|
||||
if (vcs == null) return null;
|
||||
|
||||
VcsHistoryProvider historyProvider = vcs.getVcsHistoryProvider();
|
||||
@@ -237,7 +178,8 @@ public class AnnotateStackTraceAction extends AnAction implements DumbAware {
|
||||
VcsFileRevision revision = ((VcsHistoryProviderEx)historyProvider).getLastRevision(filePath);
|
||||
if (revision == null) return null;
|
||||
return LastRevision.create(revision);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
VcsHistorySession session = historyProvider.createSessionFor(filePath);
|
||||
if (session == null) return null;
|
||||
|
||||
@@ -255,11 +197,6 @@ public class AnnotateStackTraceAction extends AnAction implements DumbAware {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(!myGutterShowed);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@CalledWithReadLock
|
||||
private static VirtualFile getHyperlinkVirtualFile(@NotNull List<RangeHighlighter> links) {
|
||||
@@ -313,4 +250,112 @@ public class AnnotateStackTraceAction extends AnAction implements DumbAware {
|
||||
return myMessage;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyActiveAnnotationGutter implements ActiveAnnotationGutter {
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final EditorHyperlinkSupport myHyperlinks;
|
||||
@NotNull private final ProgressIndicator myIndicator;
|
||||
|
||||
@NotNull private Map<Integer, LastRevision> myRevisions = Collections.emptyMap();
|
||||
private Date myNewestDate = null;
|
||||
private int myMaxDateLength = 0;
|
||||
|
||||
public MyActiveAnnotationGutter(@NotNull Project project,
|
||||
@NotNull EditorHyperlinkSupport hyperlinks,
|
||||
@NotNull ProgressIndicator indicator) {
|
||||
myProject = project;
|
||||
myHyperlinks = hyperlinks;
|
||||
myIndicator = indicator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(int lineNum) {
|
||||
LastRevision revision = myRevisions.get(lineNum);
|
||||
if (revision == null) return;
|
||||
|
||||
VirtualFile file = getHyperlinkVirtualFile(myHyperlinks.findAllHyperlinksOnLine(lineNum));
|
||||
if (file == null) return;
|
||||
|
||||
AbstractVcs vcs = ProjectLevelVcsManager.getInstance(myProject).getVcsFor(file);
|
||||
if (vcs != null) {
|
||||
VcsRevisionNumber number = revision.getNumber();
|
||||
VcsKey vcsKey = vcs.getKeyInstanceMethod();
|
||||
ShowAllAffectedGenericAction.showSubmittedFiles(myProject, number, file, vcsKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor getCursor(int lineNum) {
|
||||
return myRevisions.containsKey(lineNum) ? Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) : Cursor.getDefaultCursor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLineText(int line, Editor editor) {
|
||||
LastRevision revision = myRevisions.get(line);
|
||||
if (revision != null) {
|
||||
return String.format("%" + myMaxDateLength + "s", DateFormatUtil.formatPrettyDate(revision.getDate())) + " " + revision.getAuthor();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTip(int line, Editor editor) {
|
||||
LastRevision revision = myRevisions.get(line);
|
||||
if (revision != null) {
|
||||
return XmlStringUtil.escapeString(
|
||||
revision.getAuthor() + " " + DateFormatUtil.formatDateTime(revision.getDate()) + "\n" +
|
||||
revision.getMessage()
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EditorFontType getStyle(int line, Editor editor) {
|
||||
LastRevision revision = myRevisions.get(line);
|
||||
return revision != null && revision.getDate().equals(myNewestDate) ? EditorFontType.BOLD : EditorFontType.PLAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorKey getColor(int line, Editor editor) {
|
||||
return AnnotationSource.LOCAL.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getBgColor(int line, Editor editor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AnAction> getPopupActions(int line, Editor editor) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gutterClosed() {
|
||||
myIndicator.cancel();
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public void updateData(@NotNull Map<Integer, LastRevision> revisions) {
|
||||
myRevisions = revisions;
|
||||
|
||||
Date newestDate = null;
|
||||
int maxDateLength = 0;
|
||||
|
||||
for (LastRevision revision : myRevisions.values()) {
|
||||
Date date = revision.getDate();
|
||||
if (newestDate == null || date.after(newestDate)) {
|
||||
newestDate = date;
|
||||
}
|
||||
int length = DateFormatUtil.formatPrettyDate(date).length();
|
||||
if (length > maxDateLength) {
|
||||
maxDateLength = length;
|
||||
}
|
||||
}
|
||||
|
||||
myNewestDate = newestDate;
|
||||
myMaxDateLength = maxDateLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
|
||||
import com.intellij.openapi.project.*;
|
||||
import com.intellij.openapi.roots.*;
|
||||
@@ -119,10 +118,6 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
private final List<IndexableFileSet> myIndexableSets = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
private final Map<IndexableFileSet, Project> myIndexableSetToProjectMap = new THashMap<IndexableFileSet, Project>();
|
||||
|
||||
private static final int OK = 1;
|
||||
private static final int REQUIRES_REBUILD = 2;
|
||||
private static final Map<ID<?, ?>, AtomicInteger> ourRebuildStatus = new THashMap<ID<?, ?>, AtomicInteger>();
|
||||
|
||||
private final MessageBusConnection myConnection;
|
||||
private final FileDocumentManager myFileDocumentManager;
|
||||
private final FileTypeManagerImpl myFileTypeManager;
|
||||
@@ -521,8 +516,8 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
for (ID<?, ?> indexId : state.getIndexIDs()) {
|
||||
final UpdatableIndex<?, ?, FileContent> index = state.getIndex(indexId);
|
||||
assert index != null;
|
||||
if(ourRebuildStatus.get(indexId).get() != OK) {
|
||||
doClearIndex(indexId); // if the index was scheduled for rebuild, only clean it
|
||||
if (!RebuildStatus.isOk(indexId)) {
|
||||
index.clear(); // if the index was scheduled for rebuild, only clean it
|
||||
}
|
||||
index.dispose();
|
||||
}
|
||||
@@ -706,7 +701,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
try {
|
||||
if (isUpToDateCheckEnabled()) {
|
||||
try {
|
||||
if (ourRebuildStatus.get(indexId).get() != OK) {
|
||||
if (!RebuildStatus.isOk(indexId)) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
forceUpdate(project, filter, restrictedFile);
|
||||
@@ -1178,12 +1173,21 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
}
|
||||
}
|
||||
|
||||
private void clearIndex(@NotNull final ID<?, ?> indexId) throws StorageException {
|
||||
advanceIndexVersion(indexId);
|
||||
doClearIndex(indexId);
|
||||
void clearIndicesIfNecessary() {
|
||||
for (ID<?, ?> indexId : getState().getIndexIDs()) {
|
||||
try {
|
||||
RebuildStatus.clearIndexIfNecessary(indexId, getIndex(indexId)::clear);
|
||||
}
|
||||
catch (StorageException e) {
|
||||
requestRebuild(indexId);
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doClearIndex(ID<?, ?> indexId) throws StorageException {
|
||||
private void clearIndex(@NotNull final ID<?, ?> indexId) throws StorageException {
|
||||
advanceIndexVersion(indexId);
|
||||
|
||||
final UpdatableIndex<?, ?, FileContent> index = myState.getIndex(indexId);
|
||||
assert index != null : "Index with key " + indexId + " not found or not registered properly";
|
||||
index.clear();
|
||||
@@ -1419,10 +1423,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
@Override
|
||||
public void requestRebuild(final ID<?, ?> indexId, final Throwable throwable) {
|
||||
cleanupProcessedFlag();
|
||||
final AtomicInteger status = ourRebuildStatus.get(indexId);
|
||||
boolean requiresRebuildWasSet = status.compareAndSet(OK, REQUIRES_REBUILD);
|
||||
|
||||
if (requiresRebuildWasSet) {
|
||||
if (RebuildStatus.requestRebuild(indexId)) {
|
||||
String message = "Rebuild requested for index " + indexId;
|
||||
Application app = ApplicationManager.getApplication();
|
||||
if (app.isUnitTestMode() && app.isReadAccessAllowed() && !app.isDispatchThread()) {
|
||||
@@ -1438,34 +1439,13 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
if (!myInitialized) return;
|
||||
advanceIndexVersion(indexId);
|
||||
|
||||
final Runnable rebuildRunnable = () -> {
|
||||
final Ref<Boolean> success = Ref.create(true);
|
||||
new Task.Modal(null, "Updating index", false) {
|
||||
@Override
|
||||
public void run(@NotNull final ProgressIndicator indicator) {
|
||||
indicator.setIndeterminate(true);
|
||||
try {
|
||||
doClearIndex(indexId);
|
||||
}
|
||||
catch (StorageException e) {
|
||||
success.set(false);
|
||||
requestRebuild(indexId);
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
}.queue();
|
||||
if (success.get()) {
|
||||
scheduleIndexRebuild("checkRebuild");
|
||||
status.compareAndSet(REQUIRES_REBUILD, OK);
|
||||
}
|
||||
};
|
||||
Runnable rebuildRunnable = () -> scheduleIndexRebuild("checkRebuild");
|
||||
|
||||
if (myIsUnitTestMode) {
|
||||
rebuildRunnable.run();
|
||||
}
|
||||
else {
|
||||
// we do invoke later since we can have read lock acquired
|
||||
//noinspection SSBasedInspection
|
||||
TransactionGuard.getInstance().submitTransactionLater(app, rebuildRunnable);
|
||||
}
|
||||
}
|
||||
@@ -1646,12 +1626,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
|
||||
void updateSingleIndex(@NotNull ID<?, ?> indexId, VirtualFile file, final int inputId, @Nullable FileContent currentFC)
|
||||
throws StorageException {
|
||||
AtomicInteger rebuildStatus = ourRebuildStatus.get(indexId);
|
||||
if (rebuildStatus == null) {
|
||||
LOG.error("Problem updating " + indexId + " for " + inputId + "," + file + " with content:" + currentFC + ", initialized:" + myInitialized);
|
||||
return;
|
||||
}
|
||||
if (rebuildStatus.get() == REQUIRES_REBUILD && !myIsUnitTestMode) {
|
||||
if (!RebuildStatus.isOk(indexId) && !myIsUnitTestMode) {
|
||||
return; // the index is scheduled for rebuild, no need to update
|
||||
}
|
||||
myLocalModCount++;
|
||||
@@ -2356,7 +2331,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
public FileIndexDataInitialization(FileBasedIndexExtension[] extensions) {
|
||||
for (FileBasedIndexExtension<?, ?> extension : extensions) {
|
||||
ID<?, ?> name = extension.getName();
|
||||
ourRebuildStatus.put(name, new AtomicInteger(OK));
|
||||
RebuildStatus.registerIndex(name);
|
||||
|
||||
myUnsavedDataUpdateTasks.put(name, new DocumentUpdateTask(name));
|
||||
|
||||
@@ -2426,14 +2401,12 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
myState = state; // memory barrier
|
||||
// check if rebuild was requested for any index during registration
|
||||
for (ID<?, ?> indexId : state.getIndexIDs()) {
|
||||
if (ourRebuildStatus.get(indexId).compareAndSet(REQUIRES_REBUILD, OK)) {
|
||||
try {
|
||||
clearIndex(indexId);
|
||||
}
|
||||
catch (StorageException e) {
|
||||
requestRebuild(indexId);
|
||||
LOG.error(e);
|
||||
}
|
||||
try {
|
||||
RebuildStatus.clearIndexIfNecessary(indexId, () -> clearIndex(indexId));
|
||||
}
|
||||
catch (StorageException e) {
|
||||
requestRebuild(indexId);
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.util.indexing;
|
||||
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.util.ThrowableRunnable;
|
||||
import com.intellij.util.TimeoutUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
enum RebuildStatus {
|
||||
OK,
|
||||
REQUIRES_REBUILD,
|
||||
DOING_REBUILD;
|
||||
|
||||
private static final Map<ID<?, ?>, AtomicReference<RebuildStatus>> ourRebuildStatus = ContainerUtil.newTroveMap();
|
||||
|
||||
static void registerIndex(ID<?, ?> indexId) {
|
||||
ourRebuildStatus.put(indexId, new AtomicReference<>(OK));
|
||||
}
|
||||
|
||||
static boolean isOk(ID<?, ?> indexId) {
|
||||
return ourRebuildStatus.get(indexId).get() == OK;
|
||||
}
|
||||
|
||||
static boolean requestRebuild(ID<?, ?> indexId) {
|
||||
return ourRebuildStatus.get(indexId).compareAndSet(OK, REQUIRES_REBUILD);
|
||||
}
|
||||
|
||||
static void clearIndexIfNecessary(ID<?, ?> indexId, ThrowableRunnable<StorageException> clearAction) throws StorageException {
|
||||
AtomicReference<RebuildStatus> rebuildStatus = ourRebuildStatus.get(indexId);
|
||||
if (rebuildStatus == null) {
|
||||
throw new StorageException("Problem updating " + indexId);
|
||||
}
|
||||
|
||||
if (rebuildStatus.compareAndSet(REQUIRES_REBUILD, DOING_REBUILD)) {
|
||||
doClear(clearAction, rebuildStatus);
|
||||
} else {
|
||||
waitUntilIndexReady(rebuildStatus);
|
||||
}
|
||||
}
|
||||
|
||||
private static void doClear(ThrowableRunnable<StorageException> clearAction, AtomicReference<RebuildStatus> status) throws StorageException {
|
||||
try {
|
||||
clearAction.run();
|
||||
}
|
||||
catch (StorageException e) {
|
||||
status.compareAndSet(DOING_REBUILD, REQUIRES_REBUILD);
|
||||
throw e;
|
||||
}
|
||||
if (!status.compareAndSet(DOING_REBUILD, OK)) {
|
||||
FileBasedIndexImpl.LOG.error("Unexpected status " + status.get());
|
||||
}
|
||||
}
|
||||
|
||||
private static void waitUntilIndexReady(AtomicReference<RebuildStatus> rebuildStatus) {
|
||||
while (rebuildStatus.get() != OK) {
|
||||
ProgressManager.checkCanceled();
|
||||
TimeoutUtil.sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,7 +18,6 @@ package com.intellij.util.indexing;
|
||||
import com.intellij.ProjectTopics;
|
||||
import com.intellij.diagnostic.PerformanceWatcher;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.caches.FileContent;
|
||||
import com.intellij.ide.startup.impl.StartupManagerImpl;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -34,7 +33,6 @@ import com.intellij.openapi.roots.ModuleRootEvent;
|
||||
import com.intellij.openapi.roots.impl.PushedFilePropertiesUpdater;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
@@ -71,6 +69,8 @@ public class UnindexedFilesUpdater extends DumbModeTask {
|
||||
indicator.setIndeterminate(true);
|
||||
indicator.setText(IdeBundle.message("progress.indexing.scanning"));
|
||||
|
||||
myIndex.clearIndicesIfNecessary();
|
||||
|
||||
CollectingContentIterator finder = myIndex.createContentIterator(indicator);
|
||||
snapshot = PerformanceWatcher.takeSnapshot();
|
||||
|
||||
|
||||
@@ -36,5 +36,6 @@
|
||||
<orderEntry type="library" name="Guava" level="project" />
|
||||
<orderEntry type="library" name="http-client" level="project" />
|
||||
<orderEntry type="library" name="jna" level="project" />
|
||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -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.
|
||||
@@ -31,11 +31,8 @@ import com.intellij.openapi.util.registry.RegistryValue;
|
||||
import com.intellij.ui.LoadingNode;
|
||||
import com.intellij.ui.treeStructure.AlwaysExpandedTree;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.concurrency.WorkerThread;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.concurrency.QueueProcessor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.enumeration.EnumerationCopy;
|
||||
@@ -49,6 +46,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.concurrency.AsyncPromise;
|
||||
import org.jetbrains.concurrency.Promise;
|
||||
import org.jetbrains.concurrency.Promises;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
@@ -96,7 +94,10 @@ public class AbstractTreeUi {
|
||||
private TreeExpansionListener myExpansionListener;
|
||||
private MySelectionListener mySelectionListener;
|
||||
|
||||
private WorkerThread myWorker = null;
|
||||
private final QueueProcessor<Runnable> myWorker = new QueueProcessor<Runnable>(runnable -> {
|
||||
runnable.run();
|
||||
TimeoutUtil.sleep(1);
|
||||
});
|
||||
private final Set<Runnable> myActiveWorkerTasks = new HashSet<Runnable>();
|
||||
|
||||
private ProgressIndicator myProgress;
|
||||
@@ -455,10 +456,8 @@ public class AbstractTreeUi {
|
||||
disposeNode(getRootNode());
|
||||
myElementToNodeMap.clear();
|
||||
getUpdater().cancelAllRequests();
|
||||
if (myWorker != null) {
|
||||
myWorker.dispose(true);
|
||||
clearWorkerTasks();
|
||||
}
|
||||
myWorker.clear();
|
||||
clearWorkerTasks();
|
||||
TREE_NODE_WRAPPER.setValue(null);
|
||||
if (myProgress != null) {
|
||||
myProgress.cancel();
|
||||
@@ -468,7 +467,6 @@ public class AbstractTreeUi {
|
||||
|
||||
myTree = null;
|
||||
setUpdater(null);
|
||||
myWorker = null;
|
||||
myTreeStructure = null;
|
||||
myBuilder.releaseUi();
|
||||
myBuilder = null;
|
||||
@@ -941,7 +939,7 @@ public class AbstractTreeUi {
|
||||
return update.get();
|
||||
}
|
||||
catch (IndexNotReadyException e) {
|
||||
warnOnIndexNotReady();
|
||||
warnOnIndexNotReady(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1621,7 +1619,7 @@ public class AbstractTreeUi {
|
||||
});
|
||||
}
|
||||
catch (IndexNotReadyException e) {
|
||||
warnOnIndexNotReady();
|
||||
warnOnIndexNotReady(e);
|
||||
return ArrayUtil.EMPTY_OBJECT_ARRAY;
|
||||
}
|
||||
finally {
|
||||
@@ -1653,10 +1651,10 @@ public class AbstractTreeUi {
|
||||
return passOne.get();
|
||||
}
|
||||
|
||||
private void warnOnIndexNotReady() {
|
||||
private void warnOnIndexNotReady(IndexNotReadyException e) {
|
||||
if (!myWasEverIndexNotReady) {
|
||||
myWasEverIndexNotReady = true;
|
||||
LOG.warn("Tree is not dumb-mode-aware; treeBuilder=" + getBuilder() + " treeStructure=" + getTreeStructure());
|
||||
LOG.error("Tree is not dumb-mode-aware; treeBuilder=" + getBuilder() + " treeStructure=" + getTreeStructure(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1729,7 +1727,7 @@ public class AbstractTreeUi {
|
||||
}
|
||||
}
|
||||
}
|
||||
return Promise.all(promises);
|
||||
return Promises.all(promises);
|
||||
}
|
||||
}, pass, node);
|
||||
}
|
||||
@@ -3446,18 +3444,8 @@ public class AbstractTreeUi {
|
||||
execute(pooledThreadRunnable);
|
||||
}
|
||||
else {
|
||||
if (myWorker == null || myWorker.isDisposed()) {
|
||||
myWorker = new WorkerThread("AbstractTreeBuilder.Worker", 1);
|
||||
myWorker.start();
|
||||
myWorker.addTaskFirst(pooledThreadRunnable);
|
||||
myWorker.dispose(false);
|
||||
}
|
||||
else {
|
||||
myWorker.addTaskFirst(pooledThreadRunnable);
|
||||
}
|
||||
myWorker.addFirst(pooledThreadRunnable);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -4737,11 +4725,7 @@ public class AbstractTreeUi {
|
||||
myUnbuiltNodes.clear();
|
||||
myUpdateFromRootRequested = true;
|
||||
|
||||
if (myWorker != null) {
|
||||
Disposer.dispose(myWorker);
|
||||
myWorker = null;
|
||||
}
|
||||
|
||||
myWorker.clear();
|
||||
myTree.invalidate();
|
||||
|
||||
state.restore(null);
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.util.concurrency;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.util.TimeoutUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated use lightweight com.intellij.util.concurrency.QueueProcessor instead
|
||||
*/
|
||||
public class WorkerThread implements Runnable, Disposable {
|
||||
private final LinkedList<Runnable> myTasks = new LinkedList<Runnable>();
|
||||
private boolean myToDispose = false;
|
||||
private boolean myDisposed = false;
|
||||
private final int mySleep;
|
||||
private final String myName;
|
||||
|
||||
public WorkerThread(@NonNls String name, int sleep) {
|
||||
mySleep = sleep;
|
||||
myName = name;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(this);
|
||||
}
|
||||
|
||||
public boolean addTask(Runnable action) {
|
||||
synchronized(myTasks){
|
||||
if(myDisposed) return false;
|
||||
|
||||
myTasks.add(action);
|
||||
myTasks.notifyAll();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addTaskFirst(@NotNull Runnable action) {
|
||||
synchronized(myTasks){
|
||||
if(myDisposed) return false;
|
||||
|
||||
myTasks.add(0, action);
|
||||
myTasks.notifyAll();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
dispose(true);
|
||||
}
|
||||
|
||||
public void dispose(boolean cancelTasks){
|
||||
synchronized(myTasks){
|
||||
if (cancelTasks){
|
||||
myTasks.clear();
|
||||
}
|
||||
myToDispose = true;
|
||||
myTasks.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelTasks() {
|
||||
synchronized(myTasks){
|
||||
myTasks.clear();
|
||||
myTasks.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDisposeRequested() {
|
||||
synchronized(myTasks){
|
||||
return myToDispose;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDisposed() {
|
||||
synchronized(myTasks){
|
||||
return myDisposed;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
while (true) {
|
||||
Runnable task;
|
||||
synchronized (myTasks) {
|
||||
if (myTasks.isEmpty()) break;
|
||||
task = myTasks.removeFirst();
|
||||
}
|
||||
task.run();
|
||||
if (mySleep > 0) {
|
||||
TimeoutUtil.sleep(mySleep);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (myTasks) {
|
||||
if (myToDispose && myTasks.isEmpty()) {
|
||||
myDisposed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
myTasks.wait();
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
@file:JvmName("Promises")
|
||||
package org.jetbrains.concurrency
|
||||
|
||||
import com.intellij.util.Consumer
|
||||
|
||||
fun resolvedPromise(): Promise<*> = Promise.DONE
|
||||
|
||||
fun <T> resolvedPromise(result: T) = Promise.resolve(result)
|
||||
|
||||
fun all(promises: Collection<Promise<*>>) = if (promises.size == 1) promises.first() else all(promises, null)
|
||||
|
||||
fun <T> all(promises: Collection<Promise<*>>, totalResult: T?): Promise<T> {
|
||||
if (promises.isEmpty()) {
|
||||
return resolvedPromise(null)
|
||||
}
|
||||
|
||||
val totalPromise = AsyncPromise<T>()
|
||||
val done = CountDownConsumer(promises.size, totalPromise, totalResult)
|
||||
val rejected = Consumer<Throwable> { error -> totalPromise.setError(error) }
|
||||
|
||||
for (promise in promises) {
|
||||
promise.done(done)
|
||||
promise.rejected(rejected)
|
||||
}
|
||||
return totalPromise
|
||||
}
|
||||
|
||||
private class CountDownConsumer<T>(@Volatile private var countDown: Int, private val promise: AsyncPromise<T>, private val totalResult: T?) : Consumer<Any?> {
|
||||
override fun consume(t: Any?) {
|
||||
if (--countDown == 0) {
|
||||
promise.setResult(totalResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import com.intellij.ui.*;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.ui.components.panels.Wrapper;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.ui.Html;
|
||||
import com.intellij.util.ui.JBInsets;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
@@ -57,6 +58,7 @@ import java.awt.event.AWTEventListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
public class IdeTooltipManager implements ApplicationComponent, AWTEventListener {
|
||||
private static final String CUSTOM_TOOLTIP = "custom.tooltip";
|
||||
public static final String IDE_TOOLTIP_PLACE = "IdeTooltip";
|
||||
|
||||
public static final Color GRAPHITE_COLOR = new Color(100, 100, 100, 230);
|
||||
@@ -177,7 +179,7 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener
|
||||
}
|
||||
|
||||
String tooltipText = comp.getToolTipText(me);
|
||||
if (tooltipText == null || tooltipText.trim().isEmpty()) return;
|
||||
if ((tooltipText == null || tooltipText.trim().isEmpty()) && getCustomTooltip(comp) == null) return;
|
||||
|
||||
|
||||
boolean centerDefault = Boolean.TRUE.equals(comp.getClientProperty(UIUtil.CENTER_TOOLTIP_DEFAULT));
|
||||
@@ -199,29 +201,40 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener
|
||||
}
|
||||
|
||||
private void queueShow(final JComponent c, final MouseEvent me, final boolean toCenter, int shift, int posChangeX, int posChangeY) {
|
||||
String aText = String.valueOf(c.getToolTipText(me));
|
||||
final IdeTooltip tooltip = new IdeTooltip(c, me.getPoint(), null, /*new Object()*/c, aText) {
|
||||
@Override
|
||||
protected boolean beforeShow() {
|
||||
myCurrentEvent = me;
|
||||
IdeTooltip tooltip = getCustomTooltip(c);
|
||||
if (tooltip == null) {
|
||||
String aText = String.valueOf(c.getToolTipText(me));
|
||||
tooltip = new IdeTooltip(c, me.getPoint(), null, /*new Object()*/c, aText) {
|
||||
@Override
|
||||
protected boolean beforeShow() {
|
||||
myCurrentEvent = me;
|
||||
|
||||
if (!c.isShowing()) return false;
|
||||
if (!c.isShowing()) return false;
|
||||
|
||||
String text = c.getToolTipText(myCurrentEvent);
|
||||
if (text == null || text.trim().isEmpty()) return false;
|
||||
String text = c.getToolTipText(myCurrentEvent);
|
||||
if (text == null || text.trim().isEmpty()) return false;
|
||||
|
||||
JLayeredPane layeredPane = UIUtil.getParentOfType(JLayeredPane.class, c);
|
||||
JLayeredPane layeredPane = UIUtil.getParentOfType(JLayeredPane.class, c);
|
||||
|
||||
final JEditorPane pane = initPane(text, new HintHint(me).setAwtTooltip(true), layeredPane);
|
||||
final Wrapper wrapper = new Wrapper(pane);
|
||||
setTipComponent(wrapper);
|
||||
return true;
|
||||
}
|
||||
}.setToCenter(toCenter).setCalloutShift(shift).setPositionChangeShift(posChangeX, posChangeY).setLayer(Balloon.Layer.top);
|
||||
final JEditorPane pane = initPane(text, new HintHint(me).setAwtTooltip(true), layeredPane);
|
||||
final Wrapper wrapper = new Wrapper(pane);
|
||||
setTipComponent(wrapper);
|
||||
return true;
|
||||
}
|
||||
}.setToCenter(toCenter).setCalloutShift(shift).setPositionChangeShift(posChangeX, posChangeY).setLayer(Balloon.Layer.top);
|
||||
}
|
||||
|
||||
show(tooltip, false);
|
||||
}
|
||||
|
||||
public void setCustomTooltip(JComponent component, IdeTooltip tooltip) {
|
||||
component.putClientProperty(CUSTOM_TOOLTIP, tooltip);
|
||||
}
|
||||
|
||||
public IdeTooltip getCustomTooltip(JComponent component) {
|
||||
return ObjectUtils.tryCast(component.getClientProperty(CUSTOM_TOOLTIP), IdeTooltip.class);
|
||||
}
|
||||
|
||||
public IdeTooltip show(final IdeTooltip tooltip, boolean now) {
|
||||
return show(tooltip, now, true);
|
||||
}
|
||||
|
||||
@@ -30,9 +30,11 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.TransactionGuard;
|
||||
import com.intellij.openapi.components.ApplicationComponent;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.intellij.ui.mac.foundation.Foundation;
|
||||
import com.intellij.ui.mac.foundation.ID;
|
||||
import com.sun.jna.Callback;
|
||||
@@ -40,6 +42,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.Component;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.ICC_ColorSpace;
|
||||
import java.awt.color.ICC_Profile;
|
||||
@@ -47,12 +50,14 @@ import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class MacOSApplicationProvider implements ApplicationComponent {
|
||||
private static final Logger LOG = Logger.getInstance(MacOSApplicationProvider.class);
|
||||
private static final AtomicBoolean ENABLED = new AtomicBoolean(true);
|
||||
private static final Callback IMPL = new Callback() {
|
||||
@SuppressWarnings("unused")
|
||||
public void callback(ID self, String selector) {
|
||||
@@ -129,13 +134,13 @@ public class MacOSApplicationProvider implements ApplicationComponent {
|
||||
@Override
|
||||
public void handlePreferences(ApplicationEvent applicationEvent) {
|
||||
Project project = getNotNullProject();
|
||||
TransactionGuard.submitTransaction(project, () -> ShowSettingsAction.perform(project));
|
||||
submit(() -> ShowSettingsAction.perform(project));
|
||||
applicationEvent.setHandled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleQuit(ApplicationEvent applicationEvent) {
|
||||
TransactionGuard.submitTransaction(ApplicationManager.getApplication(), ExitAction::perform);
|
||||
submit(ExitAction::perform);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,7 +149,7 @@ public class MacOSApplicationProvider implements ApplicationComponent {
|
||||
String filename = applicationEvent.getFilename();
|
||||
if (filename == null) return;
|
||||
|
||||
TransactionGuard.submitTransaction(ApplicationManager.getApplication(), () -> {
|
||||
submit(() -> {
|
||||
File file = new File(filename);
|
||||
if (ProjectUtil.openOrImport(file.getAbsolutePath(), project, true) != null) {
|
||||
IdeaApplication.getInstance().setPerformProjectLoad(false);
|
||||
@@ -201,5 +206,22 @@ public class MacOSApplicationProvider implements ApplicationComponent {
|
||||
Project project = getProject();
|
||||
return project != null ? project : ProjectManager.getInstance().getDefaultProject();
|
||||
}
|
||||
|
||||
private static void submit(@NotNull Runnable task) {
|
||||
if (!ENABLED.get()) return;
|
||||
|
||||
Component component = IdeFocusManager.getGlobalInstance().getFocusOwner();
|
||||
if (component == null || IdeKeyEventDispatcher.isModalContext(component)) return;
|
||||
|
||||
ENABLED.set(false);
|
||||
TransactionGuard.submitTransaction(ApplicationManager.getApplication(), () -> {
|
||||
try {
|
||||
task.run();
|
||||
}
|
||||
finally {
|
||||
ENABLED.set(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.ui;
|
||||
|
||||
import com.intellij.ide.BrowserUtil;
|
||||
import com.intellij.ide.IdeTooltip;
|
||||
import com.intellij.ide.IdeTooltipManager;
|
||||
import com.intellij.ide.TooltipEvent;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import javax.swing.event.HyperlinkListener;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* Custom tooltip implementation which supports clickable links in HTML text
|
||||
*
|
||||
* @see IdeTooltipManager#setCustomTooltip(JComponent, IdeTooltip)
|
||||
*/
|
||||
public class TooltipWithClickableLinks extends IdeTooltip {
|
||||
public TooltipWithClickableLinks(JComponent component, String htmlText, HyperlinkListener hyperlinkListener) {
|
||||
super(component, new Point(), createTipComponent(htmlText, hyperlinkListener), component, htmlText);
|
||||
}
|
||||
|
||||
private static JComponent createTipComponent(String text, HyperlinkListener hyperlinkListener) {
|
||||
JEditorPane pane = IdeTooltipManager.initPane(text, new HintHint().setAwtTooltip(true), null);
|
||||
pane.addHyperlinkListener(hyperlinkListener);
|
||||
return pane;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canAutohideOn(TooltipEvent event) {
|
||||
return !event.isIsEventInsideBalloon();
|
||||
}
|
||||
|
||||
public static class ForBrowser extends TooltipWithClickableLinks {
|
||||
public ForBrowser(JComponent component, String htmlText) {
|
||||
super(component, htmlText, new HyperlinkAdapter() {
|
||||
@Override
|
||||
protected void hyperlinkActivated(HyperlinkEvent e) {
|
||||
BrowserUtil.browse(e.getURL());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ fun Path.delete() {
|
||||
}
|
||||
}
|
||||
|
||||
fun Path.deleteRecursively(): Path = if (exists()) Files.walkFileTree(this, object : SimpleFileVisitor<Path>() {
|
||||
fun Path.deleteRecursively(): Path = if (exists()) Files.walkFileTree (this, object : SimpleFileVisitor<Path>() {
|
||||
override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {
|
||||
file.delete()
|
||||
return FileVisitResult.CONTINUE
|
||||
|
||||
+1
-1
@@ -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.
|
||||
+1
-1
@@ -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.
|
||||
@@ -25,7 +25,7 @@ private val rejectedPromise = Promise.reject<Any?>("rejected")
|
||||
// only internal usage
|
||||
interface ObsolescentFunction<Param, Result> : Function<Param, Result>, Obsolescent
|
||||
|
||||
abstract class ValueNodeAsyncFunction<PARAM, RESULT>(private val node: Obsolescent) : AsyncFunction<PARAM, RESULT>, Obsolescent {
|
||||
abstract class ValueNodeAsyncFunction<PARAM, RESULT>(private val node: Obsolescent) : Function<PARAM, Promise<RESULT>>, Obsolescent {
|
||||
override fun isObsolete() = node.isObsolete
|
||||
}
|
||||
|
||||
@@ -69,9 +69,9 @@ inline fun <T> Promise<T>.thenAsyncAccept(node: Obsolescent, crossinline handler
|
||||
override fun `fun`(param: T) = handler(param) as Promise<Any?>
|
||||
})
|
||||
|
||||
inline fun <T> Promise<T>.thenAsyncAccept(crossinline handler: (T) -> Promise<*>) = thenAsync(AsyncFunction<T, kotlin.Any?> { param ->
|
||||
inline fun <T> Promise<T>.thenAsyncAccept(crossinline handler: (T) -> Promise<*>) = thenAsync(Function<T, Promise<kotlin.Any?>> { param ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(return@AsyncFunction handler(param) as Promise<Any?>)
|
||||
(return@Function handler(param) as Promise<Any?>)
|
||||
})
|
||||
|
||||
|
||||
@@ -80,15 +80,11 @@ inline fun Promise<*>.rejected(node: Obsolescent, crossinline handler: (Throwabl
|
||||
})
|
||||
|
||||
|
||||
fun resolvedPromise(): Promise<*> = Promise.DONE
|
||||
|
||||
fun <T> resolvedPromise(result: T) = Promise.resolve(result)
|
||||
|
||||
fun <T> rejectedPromise(error: String): Promise<T> = Promise.reject(error)
|
||||
|
||||
fun <T> rejectedPromise(error: Throwable): Promise<T> = Promise.reject(error)
|
||||
|
||||
@Suppress("CAST_NEVER_SUCCEEDS")
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> rejectedPromise(): Promise<T> = rejectedPromise as Promise<T>
|
||||
|
||||
val Promise<*>.isRejected: Boolean
|
||||
@@ -119,7 +115,7 @@ fun <T> collectResults(promises: List<Promise<T>>): Promise<List<T>> {
|
||||
for (promise in promises) {
|
||||
promise.done { results.add(it) }
|
||||
}
|
||||
return Promise.all(promises, results)
|
||||
return all(promises, results)
|
||||
}
|
||||
|
||||
fun createError(error: String, log: Boolean): RuntimeException = Promise.MessageError(error, log)
|
||||
|
||||
@@ -533,7 +533,7 @@ checkbox.show.only.monospaced.fonts=Show only monospaced fonts
|
||||
primary.font=Primary font:
|
||||
secondary.font=Secondary font:
|
||||
use.ligatures=Enable font ligatures
|
||||
ligatures.jre.warning=The JRE you are running {0} with might have\nfunctional and performance issues related to ligatures support.\nTo avoid such issues, run IntelliJ IDEA with the bundled JRE.
|
||||
ligatures.jre.warning=<html>The JRE you are running {0} with might have<br>functional and performance issues related to ligatures support.<br>To avoid such issues, run {0} with <a href="https://confluence.jetbrains.com/display/IDEADEV/JetBrains+Runtime+Environment">JetBrains Runtime</a>.
|
||||
editbox.enter.tag.name=Enter tag name:
|
||||
title.tag.name=Tag Name
|
||||
title.xml=XML
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.easymock.classextension.EasyMock.*;
|
||||
import static org.easymock.EasyMock.*;
|
||||
|
||||
public class SelectionHistoryDialogTest extends LocalHistoryUITestCase {
|
||||
private VirtualFile f;
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.easymock.classextension.EasyMock.*;
|
||||
import static org.easymock.EasyMock.*;
|
||||
|
||||
public class SelectionCalculatorTest extends LocalHistoryTestCase {
|
||||
IdeaGateway gw = new MyIdeaGateway();
|
||||
|
||||
Vendored
+1
-1
@@ -20,7 +20,7 @@ import com.intellij.openapi.diff.*;
|
||||
import com.intellij.openapi.fileTypes.FileTypes;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.easymock.classextension.EasyMock;
|
||||
import org.easymock.EasyMock;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -23,6 +23,7 @@ import com.intellij.util.Url
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import gnu.trove.TObjectHashingStrategy
|
||||
import org.jetbrains.concurrency.Promise
|
||||
import org.jetbrains.concurrency.all
|
||||
import org.jetbrains.concurrency.rejectedPromise
|
||||
import org.jetbrains.concurrency.resolvedPromise
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
@@ -90,7 +91,7 @@ abstract class BreakpointManagerBase<T : BreakpointBase<*>> : BreakpointManager
|
||||
promises.add(doClearBreakpoint(b))
|
||||
}
|
||||
}
|
||||
return Promise.all(promises)
|
||||
return all(promises)
|
||||
}
|
||||
|
||||
protected abstract fun doClearBreakpoint(breakpoint: T): Promise<*>
|
||||
|
||||
+7
-8
@@ -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.
|
||||
@@ -17,8 +17,9 @@ package org.jetbrains.debugger.values
|
||||
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.concurrency.Obsolescent
|
||||
import org.jetbrains.concurrency.ObsolescentAsyncFunction
|
||||
import org.jetbrains.concurrency.ObsolescentFunction
|
||||
import org.jetbrains.concurrency.Promise
|
||||
import org.jetbrains.concurrency.all
|
||||
import org.jetbrains.debugger.EvaluateContext
|
||||
import org.jetbrains.debugger.Variable
|
||||
import org.jetbrains.debugger.VariablesHost
|
||||
@@ -30,7 +31,7 @@ abstract class ObjectValueBase<VALUE_LOADER : ValueManager>(type: ValueType) : V
|
||||
override val properties: Promise<List<Variable>>
|
||||
get() = childrenManager.get()
|
||||
|
||||
internal abstract inner class MyObsolescentAsyncFunction<PARAM, RESULT>(private val obsolescent: Obsolescent) : ObsolescentAsyncFunction<PARAM, RESULT> {
|
||||
internal abstract inner class MyObsolescentAsyncFunction<PARAM, RESULT>(private val obsolescent: Obsolescent) : ObsolescentFunction<PARAM, Promise<RESULT>> {
|
||||
override fun isObsolete() = obsolescent.isObsolete || childrenManager.valueManager.isObsolete
|
||||
}
|
||||
|
||||
@@ -43,7 +44,7 @@ abstract class ObjectValueBase<VALUE_LOADER : ValueManager>(type: ValueType) : V
|
||||
|
||||
override fun getIndexedProperties(from: Int, to: Int, bucketThreshold: Int, consumer: IndexedVariablesConsumer, componentType: ValueType?): Promise<*> = Promise.REJECTED
|
||||
|
||||
@Suppress("CAST_NEVER_SUCCEEDS")
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override val variablesHost: VariablesHost<ValueManager>
|
||||
get() = childrenManager as VariablesHost<ValueManager>
|
||||
}
|
||||
@@ -57,9 +58,7 @@ fun getSpecifiedProperties(variables: List<Variable>, names: List<String>, evalu
|
||||
}
|
||||
|
||||
if (!properties.isEmpty()) {
|
||||
Collections.sort(properties, object : Comparator<Variable> {
|
||||
override fun compare(o1: Variable, o2: Variable) = names.indexOf(o1.name) - names.indexOf(o2.name)
|
||||
})
|
||||
Collections.sort(properties) { o1, o2 -> names.indexOf(o1.name) - names.indexOf(o2.name) }
|
||||
}
|
||||
|
||||
properties.add(property)
|
||||
@@ -80,6 +79,6 @@ fun getSpecifiedProperties(variables: List<Variable>, names: List<String>, evalu
|
||||
promises.add(valueModifier!!.evaluateGet(variable, evaluateContext))
|
||||
}
|
||||
}
|
||||
return Promise.all<List<Variable>>(promises, properties)
|
||||
return all(promises, properties)
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import com.intellij.xdebugger.breakpoints.XLineBreakpoint
|
||||
import gnu.trove.THashMap
|
||||
import gnu.trove.THashSet
|
||||
import org.jetbrains.concurrency.Promise
|
||||
import org.jetbrains.concurrency.all
|
||||
import org.jetbrains.concurrency.resolvedPromise
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
@@ -113,7 +114,7 @@ abstract class LineBreakpointManager(internal val debugProcess: DebugProcessImpl
|
||||
promises.add(breakpointManager.remove(vmBreakpoint))
|
||||
}
|
||||
}
|
||||
return Promise.all(promises)
|
||||
return all(promises)
|
||||
}
|
||||
|
||||
fun setBreakpoint(vm: Vm, breakpoint: XLineBreakpoint<*>, locations: List<Location>, promiseRef: Ref<Promise<out Breakpoint>>? = null) {
|
||||
@@ -233,11 +234,11 @@ abstract class LineBreakpointManager(internal val debugProcess: DebugProcessImpl
|
||||
}
|
||||
|
||||
fun clearRunToLocationBreakpoints(vm: Vm) {
|
||||
var breakpoints = synchronized (lock) {
|
||||
val breakpoints = synchronized (lock) {
|
||||
if (runToLocationBreakpoints.isEmpty) {
|
||||
return@clearRunToLocationBreakpoints
|
||||
}
|
||||
var breakpoints = runToLocationBreakpoints.toArray<Breakpoint>(arrayOfNulls<Breakpoint>(runToLocationBreakpoints.size))
|
||||
val breakpoints = runToLocationBreakpoints.toArray<Breakpoint>(arrayOfNulls<Breakpoint>(runToLocationBreakpoints.size))
|
||||
runToLocationBreakpoints.clear()
|
||||
breakpoints
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ class VariableView(override val variableName: String, private val variable: Vari
|
||||
}
|
||||
|
||||
if (hasIndexedProperties == hasNamedProperties || additionalProperties != null) {
|
||||
Promise.all(promises).processed(node) { node.addChildren(XValueChildrenList.EMPTY, true) }
|
||||
all(promises).processed(node) { node.addChildren(XValueChildrenList.EMPTY, true) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-5
@@ -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.
|
||||
@@ -18,12 +18,13 @@ package org.jetbrains.debugger;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Conditions;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.xdebugger.frame.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.concurrency.AsyncFunction;
|
||||
import org.jetbrains.concurrency.AsyncPromise;
|
||||
import org.jetbrains.concurrency.Promise;
|
||||
import org.jetbrains.concurrency.Promises;
|
||||
import org.jetbrains.debugger.values.ObjectValue;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -105,7 +106,7 @@ public class TestCompositeNode implements XCompositeNode {
|
||||
assert content == null;
|
||||
|
||||
content = new Content();
|
||||
return result.thenAsync(new AsyncFunction<XValueChildrenList, Content>() {
|
||||
return result.thenAsync(new Function<XValueChildrenList, Promise<Content>>() {
|
||||
private void resolveGroups(@NotNull List<XValueGroup> valueGroups, @NotNull List<TestCompositeNode> resultNodes, @NotNull List<Promise<?>> promises) {
|
||||
for (XValueGroup group : valueGroups) {
|
||||
TestCompositeNode node = new TestCompositeNode(group);
|
||||
@@ -115,7 +116,7 @@ public class TestCompositeNode implements XCompositeNode {
|
||||
}
|
||||
resultNodes.add(node);
|
||||
if (computeChildren) {
|
||||
promises.add(node.loadContent(Conditions.<XValueGroup>alwaysFalse(), valueSubContentResolveCondition));
|
||||
promises.add(node.loadContent(Conditions.alwaysFalse(), valueSubContentResolveCondition));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,7 +143,7 @@ public class TestCompositeNode implements XCompositeNode {
|
||||
|
||||
resolveGroups(children.getBottomGroups(), content.bottomGroups, promises);
|
||||
|
||||
return Promise.all(promises, content);
|
||||
return Promises.all(promises, content);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ import com.intellij.execution.testframework.Filter;
|
||||
import com.intellij.execution.testframework.TestConsoleProperties;
|
||||
import com.intellij.execution.testframework.sm.runner.ui.MockPrinter;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.easymock.classextension.EasyMock;
|
||||
import org.easymock.EasyMock;
|
||||
|
||||
import static com.intellij.execution.testframework.sm.runner.states.TestStateInfo.Magnitude;
|
||||
|
||||
|
||||
@@ -1,57 +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.util.containers;
|
||||
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.NULL;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public abstract class WeakFactoryMap<T,V> {
|
||||
private final ConcurrentMap<T, V> myMap = ContainerUtil.createConcurrentWeakKeyWeakValueMap();
|
||||
|
||||
protected abstract V create(T key);
|
||||
|
||||
public final V get(T key) {
|
||||
final V v = myMap.get(key);
|
||||
if (v != null) {
|
||||
return v == NULL ? null : v;
|
||||
}
|
||||
|
||||
final V value = create(key);
|
||||
V prev = myMap.putIfAbsent(key, notNull(value));
|
||||
return prev == null || prev == NULL ? value : prev;
|
||||
}
|
||||
|
||||
public final boolean containsKey(T key) {
|
||||
return myMap.containsKey(key);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
myMap.clear();
|
||||
}
|
||||
|
||||
private static <K> K notNull(K key) {
|
||||
//noinspection unchecked
|
||||
return key == null ? (K)NULL : key;
|
||||
}
|
||||
|
||||
public void put(T key, V value) {
|
||||
myMap.put(notNull(key), notNull(value));
|
||||
}
|
||||
}
|
||||
@@ -213,7 +213,7 @@ class VisiblePackBuilder {
|
||||
Set<VirtualFile> visibleRoots =
|
||||
VcsLogUtil.getAllVisibleRoots(providers.keySet(), filterCollection.getRootFilter(), filterCollection.getStructureFilter());
|
||||
|
||||
Collection<CommitId> logs = ContainerUtil.newArrayList();
|
||||
Collection<CommitId> commits = ContainerUtil.newArrayList();
|
||||
for (Map.Entry<VirtualFile, VcsLogProvider> entry : providers.entrySet()) {
|
||||
final VirtualFile root = entry.getKey();
|
||||
|
||||
@@ -230,10 +230,10 @@ class VisiblePackBuilder {
|
||||
}
|
||||
|
||||
List<TimedVcsCommit> matchingCommits = entry.getValue().getCommitsMatchingFilter(root, rootSpecificCollection, maxCount);
|
||||
logs.addAll(ContainerUtil.map(matchingCommits, commit -> new CommitId(commit.getId(), root)));
|
||||
commits.addAll(ContainerUtil.map(matchingCommits, commit -> new CommitId(commit.getId(), root)));
|
||||
}
|
||||
|
||||
return logs;
|
||||
return commits;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -135,7 +135,14 @@ public class GraphColorManagerImpl implements GraphColorManager<Integer> {
|
||||
}
|
||||
|
||||
VcsRef bestRef = ContainerUtil.sorted(ContainerUtil.concat(refs1, refs2), refManager1.getBranchLayoutComparator()).get(0);
|
||||
return refs1.contains(bestRef) ? -1 : 1;
|
||||
if (refs1.contains(bestRef)) {
|
||||
if (refs2.contains(bestRef)) {
|
||||
LOG.error(
|
||||
"Different heads " + myHashGetter.fun(head1) + " and " + myHashGetter.fun(head2) + " contain the same reference " + bestRef);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2559,6 +2559,10 @@
|
||||
key="split.try.with.multiple.resources.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.code.style.issues" enabledByDefault="true" level="INFORMATION"
|
||||
implementationClass="com.siyeh.ig.exceptions.SplitTryWithMultipleResourcesInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="SplitMultiCatch" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="split.try.with.multiple.resources.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.code.style.issues" enabledByDefault="true" level="INFORMATION"
|
||||
implementationClass="com.siyeh.ig.exceptions.SplitMultiCatchInspection"/>
|
||||
|
||||
<!--group.names.threading.issues-->
|
||||
<localInspection groupPath="Java" language="JAVA" suppressId="AccessToNonThreadSafeStaticField" shortName="AccessToNonThreadSafeStaticFieldFromInstance"
|
||||
|
||||
+2
@@ -2189,3 +2189,5 @@ replace.method.ref.with.lambda.name=Replace method reference with lambda
|
||||
replace.method.ref.with.lambda.descriptor=Replace method reference with lambda
|
||||
split.try.with.multiple.resources.name=Split Try Statement with Multiple Resources
|
||||
split.try.with.multiple.resources.descriptor=Split 'try' statement with multiple resources
|
||||
split.multi.catch.name=Split Multi-Catch into Separate Catch Blocks
|
||||
split.multi.catch.descriptor=Split multi-catch into separate 'catch' blocks
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2013 Bas Leijdekkers
|
||||
* Copyright 2010-2016 Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,6 +41,7 @@ public class FormatUtils {
|
||||
formatMethodNames.add("format");
|
||||
formatMethodNames.add("printf");
|
||||
|
||||
formatClassNames.add("java.io.Console");
|
||||
formatClassNames.add("java.io.PrintWriter");
|
||||
formatClassNames.add("java.io.PrintStream");
|
||||
formatClassNames.add("java.util.Formatter");
|
||||
|
||||
+6
-1
@@ -68,7 +68,12 @@ public class StaticInitializerReferencesSubClassInspection extends BaseJavaBatch
|
||||
scope.accept(new PsiRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (element instanceof PsiClass || element instanceof PsiReferenceParameterList || element instanceof PsiTypeElement) return;
|
||||
if (element instanceof PsiClass ||
|
||||
element instanceof PsiReferenceParameterList ||
|
||||
element instanceof PsiTypeElement ||
|
||||
element instanceof PsiLambdaExpression) {
|
||||
return;
|
||||
}
|
||||
|
||||
PsiClass targetClass = extractClass(element);
|
||||
if (targetClass != null && targetClass.isInheritor(baseClass, true) && !hasSingleInitializationPlace(targetClass)) {
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2011 Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.siyeh.ig.exceptions;
|
||||
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.assertNotNull;
|
||||
|
||||
public class SplitMultiCatchInspection extends BaseInspection {
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("split.multi.catch.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("split.multi.catch.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new SplitMultiCatchVisitor();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos) {
|
||||
return new SplitMultiCatchFix();
|
||||
}
|
||||
|
||||
private static void doFixImpl(@NotNull PsiElement element) throws IncorrectOperationException {
|
||||
final PsiElement parent = element.getParent();
|
||||
if (!(parent instanceof PsiCatchSection)) {
|
||||
return;
|
||||
}
|
||||
final PsiCatchSection catchSection = (PsiCatchSection)parent;
|
||||
final PsiElement grandParent = catchSection.getParent();
|
||||
if (!(grandParent instanceof PsiTryStatement)) {
|
||||
return;
|
||||
}
|
||||
final PsiParameter parameter = catchSection.getParameter();
|
||||
if (parameter == null) {
|
||||
return;
|
||||
}
|
||||
final PsiType type = parameter.getType();
|
||||
if (!(type instanceof PsiDisjunctionType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(element.getProject());
|
||||
final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(element.getProject());
|
||||
for (PsiType disjunction : ((PsiDisjunctionType)type).getDisjunctions()) {
|
||||
final PsiCatchSection copy = (PsiCatchSection)catchSection.copy();
|
||||
|
||||
final PsiTypeElement typeElement = assertNotNull(assertNotNull(copy.getParameter()).getTypeElement());
|
||||
final PsiTypeElement newTypeElement = factory.createTypeElementFromText(disjunction.getCanonicalText(true), catchSection);
|
||||
final PsiElement replaced = typeElement.replace(newTypeElement);
|
||||
|
||||
grandParent.addBefore(copy, catchSection);
|
||||
styleManager.shortenClassReferences(replaced);
|
||||
}
|
||||
|
||||
catchSection.delete();
|
||||
}
|
||||
|
||||
private static boolean isAcceptable(@NotNull PsiElement element) {
|
||||
final PsiElement parent = element.getParent();
|
||||
if (parent instanceof PsiCatchSection) {
|
||||
final PsiType type = ((PsiCatchSection)parent).getCatchType();
|
||||
return type instanceof PsiDisjunctionType;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class SplitMultiCatchVisitor extends BaseInspectionVisitor {
|
||||
@Override
|
||||
public void visitParameter(PsiParameter parameter) {
|
||||
super.visitParameter(parameter);
|
||||
if (isAcceptable(parameter)) {
|
||||
registerError(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitKeyword(PsiKeyword keyword) {
|
||||
super.visitKeyword(keyword);
|
||||
if (isAcceptable(keyword)) {
|
||||
registerError(keyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SplitMultiCatchFix extends InspectionGadgetsFix {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return InspectionGadgetsBundle.message("split.multi.catch.descriptor");
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFix(Project project, ProblemDescriptor descriptor) {
|
||||
doFixImpl(descriptor.getPsiElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -60,7 +60,7 @@ public class SplitTryWithMultipleResourcesInspection extends BaseInspection {
|
||||
private static void doFixImpl(@NotNull PsiElement element) throws IncorrectOperationException {
|
||||
final PsiTryStatement tryStatement = (PsiTryStatement)element.getParent();
|
||||
final PsiResourceList resourceList = tryStatement.getResourceList();
|
||||
if (resourceList == null) {
|
||||
if (resourceList == null || resourceList.getResourceVariablesCount() <= 1) {
|
||||
return;
|
||||
}
|
||||
final StringBuilder newTryStatementText = new StringBuilder();
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection splits a multi-catch section into separate <b>catch</b> blocks.
|
||||
<br><br>
|
||||
</body>
|
||||
</html>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import java.io.*;
|
||||
|
||||
public class AtCodeBlock {
|
||||
void foo() {
|
||||
try {
|
||||
Reader reader = new FileReader("");
|
||||
} catch (IndexOutOfBoundsException | FileNotFoundException e) {<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
|
||||
public class AtParameter {
|
||||
void f() {
|
||||
try {
|
||||
throw new NoRouteToHostException();
|
||||
} catch (NoRouteToHostException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SocketException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
|
||||
public class AtParameter {
|
||||
void f() {
|
||||
try {
|
||||
throw new NoRouteToHostException();
|
||||
} catch (NoRouteToHostException | SocketException | IOException<caret> e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -7,6 +7,7 @@ class Super {
|
||||
static Super USED_PRIVATE = new <warning descr="Referencing subclass MyUsedSub from superclass Super initializer might lead to class loading deadlock">MyUsedSub</warning>();
|
||||
|
||||
static Object OK_INSIDE_ANONYMOUS = new Object() {{ Sub s = new Sub(); }};
|
||||
static Runnable OK_INSIDE_LAMBDA = () -> { Sub s = new Sub(); };
|
||||
static Object OK_UNRELATED = "abc";
|
||||
static Super OK_SAME = new Super();
|
||||
static Super OK_SAME_ANONYMOUS = new Super(){};
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.siyeh.ig.fixes.exceptions;
|
||||
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.IGQuickFixesTestCase;
|
||||
import com.siyeh.ig.exceptions.SplitMultiCatchInspection;
|
||||
|
||||
public class SplitMultiCatchFixTest extends IGQuickFixesTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myFixture.enableInspections(new SplitMultiCatchInspection());
|
||||
myDefaultHint = InspectionGadgetsBundle.message("split.multi.catch.descriptor");
|
||||
myRelativePath = "exceptions/split_multi_catch";
|
||||
}
|
||||
|
||||
public void testSimple() { doTest(); }
|
||||
public void testTypeAnno() { doTest(); }
|
||||
public void testAtParameter() { doTest(); }
|
||||
public void testAtCodeBlock() { assertQuickfixNotAvailable(); }
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user