mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master' into amakeev/cmake-configs-master
This commit is contained in:
@@ -78,6 +78,12 @@ class IdeaCommunityProperties extends BaseIdeaProperties {
|
||||
String uninstallFeedbackPageUrl(ApplicationInfoProperties applicationInfo) {
|
||||
"https://www.jetbrains.com/idea/uninstall/?edition=IC-${applicationInfo.majorVersion}.${applicationInfo.minorVersion}"
|
||||
}
|
||||
|
||||
@Override
|
||||
String linkToJRE64(BuildContext buildContext) {
|
||||
def versionString = buildContext.productProperties.baseArtifactName(buildContext.applicationInfo, buildContext.buildNumber)
|
||||
return "https://download.jetbrains.com/idea/jre64-for-${versionString}.tar.gz"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -97,4 +97,12 @@ abstract class WindowsDistributionCustomizer {
|
||||
String uninstallFeedbackPageUrl(ApplicationInfoProperties applicationInfo) {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Link to a JetBrains JRE64 which is used by windows installation.
|
||||
* JRE64 will be install (optional) together with JRE x86 (not replace).
|
||||
*/
|
||||
String linkToJRE64(BuildContext buildContext) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ class BundledJreManager {
|
||||
return targetDir
|
||||
}
|
||||
|
||||
private File findJreArchive(String osDirName, JvmArchitecture arch = JvmArchitecture.x64, JreVendor vendor = JreVendor.JetBrains) {
|
||||
File findJreArchive(String osDirName, JvmArchitecture arch = JvmArchitecture.x64, JreVendor vendor = JreVendor.JetBrains) {
|
||||
def jdkDir = new File(buildContext.paths.projectHome, "build/jdk/$osDirName")
|
||||
String suffix = arch == JvmArchitecture.x32 ? "_x86" : "_x64"
|
||||
String prefix = buildContext.productProperties.toolsJarRequired ? vendor.jreWithToolsJarNamePrefix : vendor.jreNamePrefix
|
||||
|
||||
@@ -143,6 +143,7 @@ class WinExeInstallerBuilder {
|
||||
!define PRODUCT_HEADER_FILE "headerlogo.bmp"
|
||||
!define ASSOCIATION "$fileAssociations"
|
||||
!define UNINSTALL_WEB_PAGE "${customizer.uninstallFeedbackPageUrl(buildContext.applicationInfo) ?: "feedback_web_page"}"
|
||||
!define LINK_TO_JRE64 "${customizer.linkToJRE64(buildContext)}"
|
||||
|
||||
; if SHOULD_SET_DEFAULT_INSTDIR != 0 then default installation directory will be directory where highest-numbered IDE build has been installed
|
||||
; set to 1 for release build
|
||||
|
||||
@@ -82,14 +82,32 @@ class WindowsDistributionBuilder extends OsSpecificDistributionBuilder {
|
||||
void buildArtifacts(String winDistPath) {
|
||||
def arch = customizer.bundledJreArchitecture
|
||||
def jreDirectoryPath = arch != null ? buildContext.bundledJreManager.extractWinJre(arch) : null
|
||||
List<String> jreDirectoryPaths = [jreDirectoryPath];
|
||||
|
||||
if (customizer.buildZipArchive) {
|
||||
buildWinZip(jreDirectoryPath, buildContext.productProperties.buildCrossPlatformDistribution ? ".win" : "", winDistPath)
|
||||
if (customizer.linkToJRE64(buildContext) != null && arch != JvmArchitecture.x64) {
|
||||
File archive = buildContext.bundledJreManager.findJreArchive("win")
|
||||
if (archive != null) {
|
||||
//do copy of JRE64 archive
|
||||
def versionString = buildContext.productProperties.baseArtifactName(buildContext.applicationInfo, buildContext.buildNumber)
|
||||
buildContext.ant.copy(file: archive, tofile: "${buildContext.paths.artifacts}/jre64-for-${versionString}.tar.gz", overwrite: "true")
|
||||
//prepare JRE64 folder for win archive
|
||||
def jreDirectoryPath64 = buildContext.bundledJreManager.extractWinJre(JvmArchitecture.x64)
|
||||
if (! new File("${jreDirectoryPath64}/jre64").exists()) {
|
||||
buildContext.ant.move(todir: "${jreDirectoryPath64}/jre64") {
|
||||
fileset(dir: "${jreDirectoryPath64}/jre")
|
||||
}
|
||||
}
|
||||
jreDirectoryPaths = [jreDirectoryPath, jreDirectoryPath64];
|
||||
}
|
||||
}
|
||||
buildWinZip(jreDirectoryPaths, buildContext.productProperties.buildCrossPlatformDistribution ? ".win" : "", winDistPath)
|
||||
}
|
||||
|
||||
if (arch != null && customizer.buildZipWithBundledOracleJre) {
|
||||
String oracleJrePath = buildContext.bundledJreManager.extractOracleWinJre(arch)
|
||||
if (oracleJrePath != null) {
|
||||
buildWinZip(oracleJrePath, "-oracle-win", winDistPath)
|
||||
buildWinZip([oracleJrePath], "-oracle-win", winDistPath)
|
||||
}
|
||||
else {
|
||||
buildContext.messages.warning("Skipping building Windows zip archive with bundled Oracle JRE because JRE archive is missing")
|
||||
@@ -208,13 +226,15 @@ IDS_VM_OPTIONS=$vmOptions
|
||||
}
|
||||
}
|
||||
|
||||
private void buildWinZip(String jreDirectoryPath, String zipNameSuffix, String winDistPath) {
|
||||
private void buildWinZip(List<String> jreDirectoryPaths, String zipNameSuffix, String winDistPath) {
|
||||
buildContext.messages.block("Build Windows ${zipNameSuffix}.zip distribution") {
|
||||
def targetPath = "$buildContext.paths.artifacts/${buildContext.productProperties.baseArtifactName(buildContext.applicationInfo, buildContext.buildNumber)}${zipNameSuffix}.zip"
|
||||
def zipPrefix = customizer.rootDirectoryName(buildContext.applicationInfo, buildContext.buildNumber)
|
||||
def dirs = [buildContext.paths.distAll, winDistPath]
|
||||
if (jreDirectoryPath != null) {
|
||||
dirs += jreDirectoryPath
|
||||
if (jreDirectoryPaths != null) {
|
||||
jreDirectoryPaths.each {
|
||||
dirs += it
|
||||
}
|
||||
}
|
||||
buildContext.messages.progress("Building Windows ${zipNameSuffix}.zip archive")
|
||||
buildContext.ant.zip(zipfile: targetPath) {
|
||||
|
||||
+4
-4
@@ -26,6 +26,7 @@ import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.*;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.engine.requests.RequestManagerImpl;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
@@ -48,7 +49,6 @@ import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import com.sun.jdi.event.ExceptionEvent;
|
||||
import com.sun.jdi.event.LocatableEvent;
|
||||
import com.sun.jdi.request.ExceptionRequest;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.java.debugger.breakpoints.properties.JavaExceptionBreakpointProperties;
|
||||
@@ -144,9 +144,9 @@ public class ExceptionBreakpoint extends Breakpoint<JavaExceptionBreakpointPrope
|
||||
return;
|
||||
}
|
||||
// trying to create a request
|
||||
ExceptionRequest request = debugProcess.getRequestsManager().createExceptionRequest(this, refType, isNotifyCaught(),
|
||||
isNotifyUncaught());
|
||||
debugProcess.getRequestsManager().enableRequest(request);
|
||||
RequestManagerImpl manager = debugProcess.getRequestsManager();
|
||||
manager.enableRequest(manager.createExceptionRequest(this, refType, isNotifyCaught(), isNotifyUncaught()));
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
if (refType != null) {
|
||||
LOG.debug("Created exception request for reference type " + refType.name());
|
||||
|
||||
@@ -49,8 +49,6 @@ import com.sun.jdi.*;
|
||||
import com.sun.jdi.event.AccessWatchpointEvent;
|
||||
import com.sun.jdi.event.LocatableEvent;
|
||||
import com.sun.jdi.event.ModificationWatchpointEvent;
|
||||
import com.sun.jdi.request.AccessWatchpointRequest;
|
||||
import com.sun.jdi.request.ModificationWatchpointRequest;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -152,15 +150,13 @@ public class FieldBreakpoint extends BreakpointWithHighlighter<JavaFieldBreakpoi
|
||||
@Override
|
||||
protected ObjectReference getThisObject(SuspendContextImpl context, LocatableEvent event) throws EvaluateException {
|
||||
if (event instanceof ModificationWatchpointEvent) {
|
||||
ModificationWatchpointEvent modificationEvent = (ModificationWatchpointEvent)event;
|
||||
ObjectReference reference = modificationEvent.object();
|
||||
ObjectReference reference = ((ModificationWatchpointEvent)event).object();
|
||||
if (reference != null) { // non-static
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
else if (event instanceof AccessWatchpointEvent) {
|
||||
AccessWatchpointEvent accessEvent = (AccessWatchpointEvent)event;
|
||||
ObjectReference reference = accessEvent.object();
|
||||
ObjectReference reference = ((AccessWatchpointEvent)event).object();
|
||||
if (reference != null) { // non-static
|
||||
return reference;
|
||||
}
|
||||
@@ -174,29 +170,24 @@ public class FieldBreakpoint extends BreakpointWithHighlighter<JavaFieldBreakpoi
|
||||
ReferenceType refType) {
|
||||
VirtualMachineProxy vm = debugProcess.getVirtualMachineProxy();
|
||||
try {
|
||||
RequestManagerImpl manager = debugProcess.getRequestsManager();
|
||||
Field field = refType.fieldByName(getFieldName());
|
||||
if (field == null) {
|
||||
debugProcess.getRequestsManager().setInvalid(this, DebuggerBundle.message("error.invalid.breakpoint.missing.field.in.class",
|
||||
getFieldName(), refType.name()));
|
||||
manager.setInvalid(this, DebuggerBundle.message("error.invalid.breakpoint.missing.field.in.class",
|
||||
getFieldName(), refType.name()));
|
||||
return;
|
||||
}
|
||||
RequestManagerImpl manager = debugProcess.getRequestsManager();
|
||||
if (isWatchModification() && vm.canWatchFieldModification()) {
|
||||
ModificationWatchpointRequest request = manager.createModificationWatchpointRequest(this, field);
|
||||
debugProcess.getRequestsManager().enableRequest(request);
|
||||
manager.enableRequest(manager.createModificationWatchpointRequest(this, field));
|
||||
LOG.debug("Modification request added");
|
||||
}
|
||||
if (isWatchAccess() && vm.canWatchFieldAccess()) {
|
||||
AccessWatchpointRequest request = manager.createAccessWatchpointRequest(this, field);
|
||||
debugProcess.getRequestsManager().enableRequest(request);
|
||||
manager.enableRequest(manager.createAccessWatchpointRequest(this, field));
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Access request added field = "+field.name() + "; refType = "+refType.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ObjectCollectedException ex) {
|
||||
LOG.debug(ex);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
LOG.debug(ex);
|
||||
}
|
||||
@@ -221,10 +212,10 @@ public class FieldBreakpoint extends BreakpointWithHighlighter<JavaFieldBreakpoi
|
||||
final Field field = modificationEvent.field();
|
||||
if (object != null) {
|
||||
return DebuggerBundle.message(
|
||||
"status.field.watchpoint.reached.modification",
|
||||
field.declaringType().name(),
|
||||
field.name(),
|
||||
modificationEvent.valueCurrent(),
|
||||
"status.field.watchpoint.reached.modification",
|
||||
field.declaringType().name(),
|
||||
field.name(),
|
||||
modificationEvent.valueCurrent(),
|
||||
modificationEvent.valueToBe(),
|
||||
locationQName,
|
||||
locationFileName,
|
||||
@@ -233,10 +224,10 @@ public class FieldBreakpoint extends BreakpointWithHighlighter<JavaFieldBreakpoi
|
||||
);
|
||||
}
|
||||
return DebuggerBundle.message(
|
||||
"status.static.field.watchpoint.reached.modification",
|
||||
field.declaringType().name(),
|
||||
field.name(),
|
||||
modificationEvent.valueCurrent(),
|
||||
"status.static.field.watchpoint.reached.modification",
|
||||
field.declaringType().name(),
|
||||
field.name(),
|
||||
modificationEvent.valueCurrent(),
|
||||
modificationEvent.valueToBe(),
|
||||
locationQName,
|
||||
locationFileName,
|
||||
@@ -249,9 +240,9 @@ public class FieldBreakpoint extends BreakpointWithHighlighter<JavaFieldBreakpoi
|
||||
final Field field = accessEvent.field();
|
||||
if (object != null) {
|
||||
return DebuggerBundle.message(
|
||||
"status.field.watchpoint.reached.access",
|
||||
field.declaringType().name(),
|
||||
field.name(),
|
||||
"status.field.watchpoint.reached.access",
|
||||
field.declaringType().name(),
|
||||
field.name(),
|
||||
locationQName,
|
||||
locationFileName,
|
||||
locationLine,
|
||||
@@ -259,8 +250,8 @@ public class FieldBreakpoint extends BreakpointWithHighlighter<JavaFieldBreakpoi
|
||||
);
|
||||
}
|
||||
return DebuggerBundle.message(
|
||||
"status.static.field.watchpoint.reached.access",
|
||||
field.declaringType().name(),
|
||||
"status.static.field.watchpoint.reached.access",
|
||||
field.declaringType().name(),
|
||||
field.name(),
|
||||
locationQName,
|
||||
locationFileName,
|
||||
|
||||
@@ -169,7 +169,7 @@ public class MethodBreakpoint extends BreakpointWithHighlighter<JavaMethodBreakp
|
||||
case Opcodes.ARETURN:
|
||||
case Opcodes.LRETURN:
|
||||
case Opcodes.DRETURN:
|
||||
case Opcodes.ATHROW:
|
||||
//case Opcodes.ATHROW:
|
||||
allLineLocations.stream()
|
||||
.filter(l -> l.lineNumber() == myLastLine)
|
||||
.findFirst().ifPresent(location -> createLocationBreakpointRequest(location, debugProcess));
|
||||
|
||||
+1
-2
@@ -267,8 +267,7 @@ public class JavaBreakpointFiltersPanel<T extends JavaBreakpointProperties, B ex
|
||||
}
|
||||
}
|
||||
}
|
||||
StreamEx.of(myInstanceFilters).remove(InstanceFilter::isEnabled).forEach(idxs::add);
|
||||
myInstanceFilters = idxs.toArray(new InstanceFilter[idxs.size()]);
|
||||
myInstanceFilters = StreamEx.of(myInstanceFilters).remove(InstanceFilter::isEnabled).prepend(idxs).toArray(InstanceFilter[]::new);
|
||||
}
|
||||
|
||||
private static String concatWithEx(List<String> s, String concator, int N, String NthConcator) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.
|
||||
@@ -35,7 +35,6 @@ import com.intellij.psi.util.PsiClassUtil;
|
||||
import com.intellij.ui.ColoredListCellRenderer;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Processor;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
@@ -85,7 +84,7 @@ public class InheritorChooser {
|
||||
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
|
||||
final boolean isJUnit5 = ApplicationManager.getApplication().runReadAction((Computable<Boolean>)() -> JUnitUtil.isJUnit5(containingClass));
|
||||
ClassInheritorsSearch.search(containingClass).forEach(aClass -> {
|
||||
if (PsiClassUtil.isRunnableClass(aClass, !isJUnit5, true)) {
|
||||
if (isJUnit5 && JUnitUtil.isJUnit5TestClass(aClass, true) || PsiClassUtil.isRunnableClass(aClass, true, true)) {
|
||||
classes.add(aClass);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.
|
||||
@@ -138,8 +138,8 @@ public class JUnitUtil {
|
||||
|
||||
public static boolean isTestClass(@NotNull PsiClass psiClass, boolean checkAbstract, boolean checkForTestCaseInheritance) {
|
||||
if (psiClass.getQualifiedName() == null) return false;
|
||||
if (isJUnit5(psiClass)) {
|
||||
return isJUnit5TestClass(psiClass, checkAbstract);
|
||||
if (isJUnit5(psiClass) && isJUnit5TestClass(psiClass, checkAbstract)) {
|
||||
return true;
|
||||
}
|
||||
final PsiClass topLevelClass = PsiTreeUtil.getTopmostParentOfType(psiClass, PsiClass.class);
|
||||
if (topLevelClass != null) {
|
||||
|
||||
+2
-2
@@ -656,13 +656,13 @@ public class HighlightMethodUtil {
|
||||
if (methodCandidate2 != null) {
|
||||
PsiMethod element1 = methodCandidate1.getElement();
|
||||
String m1 = PsiFormatUtil.formatMethod(element1,
|
||||
methodCandidate1.getSubstitutor(),
|
||||
methodCandidate1.getSubstitutor(false),
|
||||
PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME |
|
||||
PsiFormatUtilBase.SHOW_PARAMETERS,
|
||||
PsiFormatUtilBase.SHOW_TYPE);
|
||||
PsiMethod element2 = methodCandidate2.getElement();
|
||||
String m2 = PsiFormatUtil.formatMethod(element2,
|
||||
methodCandidate2.getSubstitutor(),
|
||||
methodCandidate2.getSubstitutor(false),
|
||||
PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME |
|
||||
PsiFormatUtilBase.SHOW_PARAMETERS,
|
||||
PsiFormatUtilBase.SHOW_TYPE);
|
||||
|
||||
@@ -56,6 +56,7 @@ abstract class MigrateToStreamFix implements LocalQuickFix {
|
||||
if (!FileModificationService.getInstance().preparePsiElementForWrite(loopStatement)) return;
|
||||
PsiElement result = migrate(project, loopStatement, body, tb);
|
||||
if(result != null) {
|
||||
source.cleanUpSource();
|
||||
simplifyAndFormat(project, result);
|
||||
}
|
||||
}
|
||||
|
||||
+179
-22
@@ -390,23 +390,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
return consumerClass != null ? psiFacade.getElementFactory().createType(consumerClass, variable.getType()) : null;
|
||||
}
|
||||
|
||||
static boolean isVariableSuitableForStream(PsiVariable variable, PsiStatement statement) {
|
||||
PsiElement declaration = variable.getParent();
|
||||
// For-loop initializer is not effectively final, but suitable for stream conversion
|
||||
if(declaration instanceof PsiDeclarationStatement) {
|
||||
PsiElement grandParent = declaration.getParent();
|
||||
if (grandParent instanceof PsiForStatement) {
|
||||
PsiForStatement forStatement = (PsiForStatement)grandParent;
|
||||
if (forStatement.getInitialization() == declaration) {
|
||||
PsiStatement body = forStatement.getBody();
|
||||
if(body != null && PsiTreeUtil.isAncestor(statement, body, false)) {
|
||||
return ReferencesSearch.search(variable, new LocalSearchScope(body)).forEach(ref -> {
|
||||
PsiElement element = ref.getElement();
|
||||
return !(element instanceof PsiExpression) || !PsiUtil.isAccessedForWriting((PsiExpression)element);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
static boolean isVariableSuitableForStream(PsiVariable variable, PsiStatement statement, TerminalBlock tb) {
|
||||
if(ReferencesSearch.search(variable, variable.getUseScope()).forEach(ref -> {
|
||||
PsiElement element = ref.getElement();
|
||||
return !(element instanceof PsiExpression) ||
|
||||
!PsiUtil.isAccessedForWriting((PsiExpression)element) ||
|
||||
tb.operations().anyMatch(op -> op.isWriteAllowed(variable, (PsiExpression)element));
|
||||
})) {
|
||||
return true;
|
||||
}
|
||||
return HighlightControlFlowUtil.isEffectivelyFinal(variable, statement, null);
|
||||
}
|
||||
@@ -429,6 +420,58 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether variable can be referenced between start and loop entry. Back-edges are also considered, so the actual place
|
||||
* where it referenced might be outside of (start, loop entry) interval.
|
||||
*
|
||||
* @param flow ControlFlow to analyze
|
||||
* @param start start point
|
||||
* @param loop loop to check
|
||||
* @param variable variable to analyze
|
||||
* @return true if variable can be referenced between start and stop points
|
||||
*/
|
||||
private static boolean isVariableReferencedBeforeLoopEntry(final ControlFlow flow,
|
||||
final int start,
|
||||
final PsiLoopStatement loop,
|
||||
final PsiVariable variable) {
|
||||
final int loopStart = flow.getStartOffset(loop);
|
||||
final int loopEnd = flow.getEndOffset(loop);
|
||||
if(start == loopStart) return false;
|
||||
|
||||
List<ControlFlowUtil.ControlFlowEdge> edges = ControlFlowUtil.getEdges(flow, start);
|
||||
// DFS visits instructions mainly in backward direction while here visiting in forward direction
|
||||
// greatly reduces number of iterations.
|
||||
Collections.reverse(edges);
|
||||
|
||||
BitSet referenced = new BitSet();
|
||||
boolean changed = true;
|
||||
while(changed) {
|
||||
changed = false;
|
||||
for(ControlFlowUtil.ControlFlowEdge edge: edges) {
|
||||
int from = edge.myFrom;
|
||||
int to = edge.myTo;
|
||||
if(referenced.get(from)) {
|
||||
// jump to the loop start from within the loop is not considered as loop entry
|
||||
if(to == loopStart && (from < loopStart || from >= loopEnd)) {
|
||||
return true;
|
||||
}
|
||||
if(!referenced.get(to)) {
|
||||
referenced.set(to);
|
||||
changed = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(ControlFlowUtil.isVariableAccess(flow, from, variable)) {
|
||||
referenced.set(from);
|
||||
referenced.set(to);
|
||||
if(to == loopStart) return true;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
enum InitializerUsageStatus {
|
||||
// Variable is declared just before the wanted place
|
||||
DECLARED_JUST_BEFORE,
|
||||
@@ -440,7 +483,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
static InitializerUsageStatus getInitializerUsageStatus(PsiVariable var, PsiStatement nextStatement) {
|
||||
static InitializerUsageStatus getInitializerUsageStatus(PsiVariable var, PsiLoopStatement nextStatement) {
|
||||
if(!(var instanceof PsiLocalVariable) || var.getInitializer() == null) return UNKNOWN;
|
||||
if(isDeclarationJustBefore(var, nextStatement)) return DECLARED_JUST_BEFORE;
|
||||
// Check that variable is declared in the same method or the same lambda expression
|
||||
@@ -458,7 +501,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
int start = controlFlow.getEndOffset(var.getInitializer())+1;
|
||||
int stop = controlFlow.getStartOffset(nextStatement);
|
||||
if(ControlFlowUtil.isVariableReferencedBetween(controlFlow, start, stop, var)) return UNKNOWN;
|
||||
if(isVariableReferencedBeforeLoopEntry(controlFlow, start, nextStatement, var)) return UNKNOWN;
|
||||
if (!ControlFlowUtil.isValueUsedWithoutVisitingStop(controlFlow, start, stop, var)) return AT_WANTED_PLACE_ONLY;
|
||||
return var.hasModifierProperty(PsiModifier.FINAL) ? UNKNOWN : AT_WANTED_PLACE;
|
||||
}
|
||||
@@ -494,6 +537,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
processLoop(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhileStatement(PsiWhileStatement statement) {
|
||||
super.visitWhileStatement(statement);
|
||||
processLoop(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitForStatement(PsiForStatement statement) {
|
||||
super.visitForStatement(statement);
|
||||
@@ -524,7 +573,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
int startOffset = controlFlow.getStartOffset(body);
|
||||
int endOffset = controlFlow.getEndOffset(body);
|
||||
final List<PsiVariable> nonFinalVariables = StreamEx.of(ControlFlowUtil.getUsedVariables(controlFlow, startOffset, endOffset))
|
||||
.remove(variable -> isVariableSuitableForStream(variable, statement)).toList();
|
||||
.remove(variable -> isVariableSuitableForStream(variable, statement, tb)).toList();
|
||||
|
||||
if (exitPoints.isEmpty()) {
|
||||
if(getIncrementedVariable(tb, nonFinalVariables) != null) {
|
||||
@@ -679,6 +728,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
PsiStatement initialization = ((PsiForStatement)statement).getInitialization();
|
||||
LOG.assertTrue(initialization != null);
|
||||
return initialization.getTextRange();
|
||||
} else if(statement instanceof PsiWhileStatement) {
|
||||
PsiJavaToken rParenth = ((PsiWhileStatement)statement).getRParenth();
|
||||
if (wholeStatement && rParenth != null) {
|
||||
return new TextRange(statement.getTextOffset(), rParenth.getTextOffset() + 1);
|
||||
}
|
||||
return statement.getFirstChild().getTextRange();
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected statement type: "+statement);
|
||||
}
|
||||
@@ -830,6 +885,10 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
|
||||
abstract String createReplacement();
|
||||
|
||||
boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static class FilterOp extends Operation {
|
||||
@@ -921,6 +980,11 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
PsiExpression expression = myType == null ? myExpression : RefactoringUtil.convertInitializerToNormalExpression(myExpression, myType);
|
||||
return "." + operationName + "(" + LambdaUtil.createLambda(myVariable, expression) + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) {
|
||||
return variable == myVariable && reference.getParent() == myExpression.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
static class FlatMapOp extends Operation {
|
||||
@@ -954,6 +1018,11 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
return mySource.createReplacement();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) {
|
||||
return mySource.isWriteAllowed(variable, reference);
|
||||
}
|
||||
|
||||
boolean breaksMe(PsiBreakStatement statement) {
|
||||
return statement.findExitedStatement() == myLoop;
|
||||
}
|
||||
@@ -964,6 +1033,9 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
super(null, expression, variable);
|
||||
}
|
||||
|
||||
void cleanUpSource() {
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
static StreamSource tryCreate(PsiLoopStatement statement) {
|
||||
if(statement instanceof PsiForStatement) {
|
||||
@@ -973,10 +1045,74 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
ArrayStream source = ArrayStream.from((PsiForeachStatement)statement);
|
||||
return source == null ? CollectionStream.from((PsiForeachStatement)statement) : source;
|
||||
}
|
||||
if(statement instanceof PsiWhileStatement) {
|
||||
return BufferedReaderLines.from((PsiWhileStatement)statement);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class BufferedReaderLines extends StreamSource {
|
||||
private BufferedReaderLines(PsiVariable variable, PsiExpression expression) {
|
||||
super(variable, expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
String createReplacement() {
|
||||
return myExpression.getText()+".lines()";
|
||||
}
|
||||
|
||||
@Override
|
||||
void cleanUpSource() {
|
||||
myVariable.delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) {
|
||||
return myVariable == variable && reference.getParent() == PsiTreeUtil.getParentOfType(myExpression, PsiAssignmentExpression.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static BufferedReaderLines from(PsiWhileStatement whileLoop) {
|
||||
// while ((line = br.readLine()) != null)
|
||||
PsiExpression condition = PsiUtil.skipParenthesizedExprDown(whileLoop.getCondition());
|
||||
if(!(condition instanceof PsiBinaryExpression)) return null;
|
||||
PsiBinaryExpression binOp = (PsiBinaryExpression)condition;
|
||||
if(!JavaTokenType.NE.equals(binOp.getOperationTokenType())) return null;
|
||||
PsiExpression operand = null;
|
||||
if(ExpressionUtils.isNullLiteral(binOp.getROperand())) {
|
||||
operand = binOp.getLOperand();
|
||||
} else if(ExpressionUtils.isNullLiteral(binOp.getLOperand())) {
|
||||
operand = binOp.getROperand();
|
||||
}
|
||||
if(operand == null) return null;
|
||||
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(PsiUtil.skipParenthesizedExprDown(operand));
|
||||
if(assignment == null) return null;
|
||||
PsiExpression lValue = assignment.getLExpression();
|
||||
if(!(lValue instanceof PsiReferenceExpression)) return null;
|
||||
PsiElement element = ((PsiReferenceExpression)lValue).resolve();
|
||||
if(!(element instanceof PsiLocalVariable)) return null;
|
||||
PsiLocalVariable var = (PsiLocalVariable)element;
|
||||
if(!ReferencesSearch.search(var, var.getUseScope()).forEach(ref -> {
|
||||
return PsiTreeUtil.isAncestor(whileLoop, ref.getElement(), true);
|
||||
})) {
|
||||
return null;
|
||||
}
|
||||
PsiExpression rValue = PsiUtil.skipParenthesizedExprDown(assignment.getRExpression());
|
||||
if(!(rValue instanceof PsiMethodCallExpression)) return null;
|
||||
PsiMethodCallExpression call = (PsiMethodCallExpression)rValue;
|
||||
if(call.getArgumentList().getExpressions().length != 0) return null;
|
||||
if(!"readLine".equals(call.getMethodExpression().getReferenceName())) return null;
|
||||
PsiExpression readerExpression = call.getMethodExpression().getQualifierExpression();
|
||||
if(readerExpression == null) return null;
|
||||
PsiMethod method = call.resolveMethod();
|
||||
if(method == null) return null;
|
||||
PsiClass aClass = method.getContainingClass();
|
||||
if(aClass == null || !"java.io.BufferedReader".equals(aClass.getQualifiedName())) return null;
|
||||
return new BufferedReaderLines(var, readerExpression);
|
||||
}
|
||||
}
|
||||
|
||||
static class ArrayStream extends StreamSource {
|
||||
private ArrayStream(PsiVariable variable, PsiExpression expression) {
|
||||
super(variable, expression);
|
||||
@@ -1063,6 +1199,17 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
return className+"."+methodName+"("+myExpression.getText()+", "+myBound.getText()+")";
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) {
|
||||
if(variable == myVariable) {
|
||||
PsiForStatement forStatement = PsiTreeUtil.getParentOfType(variable, PsiForStatement.class);
|
||||
if(forStatement != null) {
|
||||
return PsiTreeUtil.isAncestor(forStatement.getUpdate(), reference, false);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CountingLoop from(PsiForStatement forStatement) {
|
||||
// check that initialization is for(int/long i = <initial_value>;...;...)
|
||||
@@ -1224,7 +1371,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
if(source == null || body == null) return null;
|
||||
// flatMap from primitive to primitive is supported only if primitive types match
|
||||
// otherwise it would be necessary to create bogus step like
|
||||
// .mapToObj(var -> blahblah.stream()).flatMap(Function.identity())
|
||||
// .mapToObj(var -> collection.stream()).flatMap(Function.identity())
|
||||
if(myVariable.getType() instanceof PsiPrimitiveType && !myVariable.getType().equals(source.getVariable().getType())) return null;
|
||||
FlatMapOp op = new FlatMapOp(myPreviousOp, source, myVariable, loopStatement);
|
||||
TerminalBlock withFlatMap = new TerminalBlock(op, source.getVariable(), body);
|
||||
@@ -1268,6 +1415,16 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
}
|
||||
}
|
||||
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(first);
|
||||
if(assignment != null) {
|
||||
PsiExpression lValue = assignment.getLExpression();
|
||||
PsiExpression rValue = assignment.getRExpression();
|
||||
if(rValue != null && lValue instanceof PsiReferenceExpression && ((PsiReferenceExpression)lValue).isReferenceTo(myVariable)) {
|
||||
PsiStatement[] leftOver = Arrays.copyOfRange(myStatements, 1, myStatements.length);
|
||||
MapOp op = new MapOp(myPreviousOp, rValue, myVariable, myVariable.getType());
|
||||
return new TerminalBlock(op, myVariable, leftOver);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1300,7 +1457,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StreamEx<Operation> operations() {
|
||||
StreamEx<Operation> operations() {
|
||||
return StreamEx.iterate(myPreviousOp, Objects::nonNull, Operation::getPreviousOp);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.
|
||||
@@ -45,7 +45,9 @@ import com.intellij.refactoring.listeners.RefactoringEventData;
|
||||
import com.intellij.refactoring.listeners.RefactoringEventListener;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.refactoring.util.InlineUtil;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Query;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -96,7 +98,7 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
|
||||
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);
|
||||
final PsiElement parentPsiClass = PsiTreeUtil.getParentOfType(innerClass.getParent(), PsiClass.class, PsiLambdaExpression.class);
|
||||
if (parentPsiClass == containingClass) {
|
||||
if (innerClass instanceof PsiLambdaExpression) {
|
||||
if (PsiTreeUtil.isAncestor(innerClass, local, false)) {
|
||||
|
||||
+11
-11
@@ -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.
|
||||
@@ -54,8 +54,6 @@ import com.intellij.psi.impl.source.jsp.jspJava.JspCodeBlock;
|
||||
import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.psi.impl.source.tree.java.ReplaceExpressionUtil;
|
||||
import com.intellij.psi.scope.processor.VariablesProcessor;
|
||||
import com.intellij.psi.scope.util.PsiScopesUtil;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.refactoring.*;
|
||||
import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer;
|
||||
@@ -755,14 +753,16 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
boolean skipForStatement = true;
|
||||
final PsiForStatement forStatement = PsiTreeUtil.getParentOfType(expr, PsiForStatement.class);
|
||||
if (forStatement != null) {
|
||||
final VariablesProcessor variablesProcessor = new VariablesProcessor(false) {
|
||||
@Override
|
||||
protected boolean check(PsiVariable var, ResolveState state) {
|
||||
return PsiTreeUtil.isAncestor(forStatement.getInitialization(), var, true);
|
||||
}
|
||||
};
|
||||
PsiScopesUtil.treeWalkUp(variablesProcessor, expr, null);
|
||||
skipForStatement = variablesProcessor.size() == 0;
|
||||
Set<PsiVariable> vars = new HashSet<>();
|
||||
SyntaxTraverser.psiTraverser().withRoot(expr)
|
||||
.filter(element -> element instanceof PsiReferenceExpression)
|
||||
.forEach(element -> {
|
||||
final PsiElement resolve = ((PsiReferenceExpression)element).resolve();
|
||||
if (resolve instanceof PsiVariable) {
|
||||
vars.add((PsiVariable)resolve);
|
||||
}
|
||||
});
|
||||
skipForStatement = vars.stream().noneMatch(variable -> PsiTreeUtil.isAncestor(forStatement.getInitialization(), variable, true));
|
||||
}
|
||||
|
||||
PsiElement containerParent = tempContainer;
|
||||
|
||||
+17
-20
@@ -19,7 +19,7 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.refactoring.typeMigration.usageInfo.OverridenUsageInfo;
|
||||
import com.intellij.refactoring.typeMigration.usageInfo.OverriddenUsageInfo;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -34,7 +34,7 @@ class MigrateGetterNameSetting {
|
||||
|
||||
private final AtomicReference<Boolean> myGlobalValue = new AtomicReference<>();
|
||||
|
||||
void askUserIfNeed(final OverridenUsageInfo info, final String newMethodName, final PsiType migrationReturnType) {
|
||||
void askUserIfNeed(final OverriddenUsageInfo info, final String newMethodName, final PsiType migrationReturnType) {
|
||||
final Boolean globalValue = myGlobalValue.get();
|
||||
if (globalValue == null) {
|
||||
final String currentName = ((PsiMethod)info.getElement()).getName();
|
||||
@@ -42,26 +42,23 @@ class MigrateGetterNameSetting {
|
||||
currentName,
|
||||
newMethodName,
|
||||
migrationReturnType.getCanonicalText());
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Boolean globalValue = myGlobalValue.get();
|
||||
if (globalValue == null) {
|
||||
final int code = showChooserDialog(messageText);
|
||||
if (code == 0) {
|
||||
myGlobalValue.set(true);
|
||||
info.setMigrateMethodName(newMethodName);
|
||||
}
|
||||
else if (code == 1) {
|
||||
info.setMigrateMethodName(newMethodName);
|
||||
}
|
||||
else if (code == 2) {
|
||||
myGlobalValue.set(false);
|
||||
}
|
||||
}
|
||||
else if (globalValue.equals(Boolean.TRUE)) {
|
||||
UIUtil.invokeAndWaitIfNeeded((Runnable)() -> {
|
||||
final Boolean globalValue1 = myGlobalValue.get();
|
||||
if (globalValue1 == null) {
|
||||
final int code = showChooserDialog(messageText);
|
||||
if (code == 0) {
|
||||
myGlobalValue.set(true);
|
||||
info.setMigrateMethodName(newMethodName);
|
||||
}
|
||||
else if (code == 1) {
|
||||
info.setMigrateMethodName(newMethodName);
|
||||
}
|
||||
else if (code == 2) {
|
||||
myGlobalValue.set(false);
|
||||
}
|
||||
}
|
||||
else if (globalValue1.equals(Boolean.TRUE)) {
|
||||
info.setMigrateMethodName(newMethodName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
-9
@@ -46,15 +46,6 @@ public class TypeConversionDescriptorBase {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return substitutor of converted method parameters
|
||||
* or null if expression is not method call expression
|
||||
*/
|
||||
@Nullable
|
||||
public PsiSubstitutor getConvertedMethodParameters() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException {
|
||||
return expression;
|
||||
}
|
||||
|
||||
@@ -348,14 +348,14 @@ public class TypeEvaluator {
|
||||
}
|
||||
|
||||
public String getReport() {
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
|
||||
final String[] t = new String[myTypeMap.size()];
|
||||
int k = 0;
|
||||
|
||||
for (final TypeMigrationUsageInfo info : myTypeMap.keySet()) {
|
||||
final LinkedList<PsiType> types = myTypeMap.get(info);
|
||||
final StringBuffer b = new StringBuffer();
|
||||
final StringBuilder b = new StringBuilder();
|
||||
|
||||
if (types != null) {
|
||||
b.append(info.getElement()).append(" : ");
|
||||
|
||||
+11
-12
@@ -38,7 +38,7 @@ import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.refactoring.rename.RenameProcessor;
|
||||
import com.intellij.refactoring.typeCook.deductive.PsiExtendedTypeVisitor;
|
||||
import com.intellij.refactoring.typeMigration.usageInfo.OverridenUsageInfo;
|
||||
import com.intellij.refactoring.typeMigration.usageInfo.OverriddenUsageInfo;
|
||||
import com.intellij.refactoring.typeMigration.usageInfo.OverriderUsageInfo;
|
||||
import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
@@ -88,7 +88,7 @@ public class TypeMigrationLabeler {
|
||||
private final Set<TypeMigrationUsageInfo> myProcessedRoots = new HashSet<>();
|
||||
|
||||
public TypeMigrationLabeler(final TypeMigrationRules rules, PsiType rootType) {
|
||||
this(rules, Functions.<PsiElement, PsiType>constant(rootType));
|
||||
this(rules, Functions.constant(rootType));
|
||||
}
|
||||
|
||||
public TypeMigrationLabeler(final TypeMigrationRules rules, Function<PsiElement, PsiType> migrationRootTypeFunction) {
|
||||
@@ -339,8 +339,8 @@ public class TypeMigrationLabeler {
|
||||
}
|
||||
else {
|
||||
TypeMigrationReplacementUtil.migrateMemberOrVariableType(element, project, getTypeEvaluator().getType(usageInfo));
|
||||
if (usageInfo instanceof OverridenUsageInfo) {
|
||||
final String migrationName = ((OverridenUsageInfo)usageInfo).getMigrateMethodName();
|
||||
if (usageInfo instanceof OverriddenUsageInfo) {
|
||||
final String migrationName = ((OverriddenUsageInfo)usageInfo).getMigrateMethodName();
|
||||
if (migrationName != null) {
|
||||
ApplicationManager.getApplication().invokeLater(() -> new RenameProcessor(project, element, migrationName, false, false).run());
|
||||
}
|
||||
@@ -662,12 +662,12 @@ public class TypeMigrationLabeler {
|
||||
for (int i = -1; i < methods.length; i++) {
|
||||
final TypeMigrationUsageInfo m;
|
||||
if (i < 0) {
|
||||
final OverridenUsageInfo overridenUsageInfo = new OverridenUsageInfo(method);
|
||||
m = overridenUsageInfo;
|
||||
final OverriddenUsageInfo overriddenUsageInfo = new OverriddenUsageInfo(method);
|
||||
m = overriddenUsageInfo;
|
||||
final String newMethodName = isMethodNameCanBeChanged(method);
|
||||
if (newMethodName != null) {
|
||||
final MigrateGetterNameSetting migrateGetterNameSetting = myRules.getConversionSettings(MigrateGetterNameSetting.class);
|
||||
migrateGetterNameSetting.askUserIfNeed(overridenUsageInfo, newMethodName, myTypeEvaluator.getType(myCurrentRoot));
|
||||
migrateGetterNameSetting.askUserIfNeed(overriddenUsageInfo, newMethodName, myTypeEvaluator.getType(myCurrentRoot));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -687,13 +687,13 @@ public class TypeMigrationLabeler {
|
||||
final PsiMethod[] methods = OverridingMethodsSearch.search(method).toArray(PsiMethod.EMPTY_ARRAY);
|
||||
|
||||
final OverriderUsageInfo[] overriders = new OverriderUsageInfo[methods.length];
|
||||
final OverridenUsageInfo overridenUsageInfo = new OverridenUsageInfo(method.getParameterList().getParameters()[index]);
|
||||
final OverriddenUsageInfo overriddenUsageInfo = new OverriddenUsageInfo(method.getParameterList().getParameters()[index]);
|
||||
for (int i = -1; i < methods.length; i++) {
|
||||
final PsiMethod m = i < 0 ? method : methods[i];
|
||||
final PsiParameter p = m.getParameterList().getParameters()[index];
|
||||
final TypeMigrationUsageInfo paramUsageInfo;
|
||||
if (i < 0) {
|
||||
paramUsageInfo = overridenUsageInfo;
|
||||
paramUsageInfo = overriddenUsageInfo;
|
||||
}
|
||||
else {
|
||||
overriders[i] = new OverriderUsageInfo(p, method);
|
||||
@@ -924,7 +924,7 @@ public class TypeMigrationLabeler {
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(validReferences, (o1, o2) -> o1.getElement().getTextOffset() - o2.getElement().getTextOffset());
|
||||
Collections.sort(validReferences, Comparator.comparingInt(o -> o.getElement().getTextOffset()));
|
||||
|
||||
return validReferences.toArray(new PsiReference[validReferences.size()]);
|
||||
}
|
||||
@@ -1040,8 +1040,7 @@ public class TypeMigrationLabeler {
|
||||
}
|
||||
|
||||
private void iterate() {
|
||||
final LinkedList<Pair<TypeMigrationUsageInfo, PsiType>> roots =
|
||||
(LinkedList<Pair<TypeMigrationUsageInfo, PsiType>>)myMigrationRoots.clone();
|
||||
final List<Pair<TypeMigrationUsageInfo, PsiType>> roots = new ArrayList<>(myMigrationRoots);
|
||||
|
||||
myMigrationRoots = new LinkedList<>();
|
||||
|
||||
|
||||
+2
-3
@@ -45,11 +45,10 @@ import java.util.*;
|
||||
import static com.intellij.util.ObjectUtils.assertNotNull;
|
||||
|
||||
public class TypeMigrationProcessor extends BaseRefactoringProcessor {
|
||||
private final static Logger LOG = Logger.getInstance(TypeMigrationProcessor.class);
|
||||
private final static int MAX_ROOT_IN_PREVIEW_PRESENTATION = 3;
|
||||
|
||||
private PsiElement[] myRoot;
|
||||
private Function<PsiElement, PsiType> myRootTypes;
|
||||
private final Function<PsiElement, PsiType> myRootTypes;
|
||||
private final TypeMigrationRules myRules;
|
||||
private TypeMigrationLabeler myLabeler;
|
||||
|
||||
@@ -74,7 +73,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
|
||||
final PsiElement root,
|
||||
final PsiType migrationType,
|
||||
final boolean optimizeImports) {
|
||||
runHighlightingTypeMigration(project, editor, rules, new PsiElement[] {root}, Functions.<PsiElement, PsiType>constant(migrationType), optimizeImports);
|
||||
runHighlightingTypeMigration(project, editor, rules, new PsiElement[] {root}, Functions.constant(migrationType), optimizeImports);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -202,7 +202,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor {
|
||||
final PsiType valueType = myTypeEvaluator.evaluateType(value);
|
||||
if (returnType != null && valueType != null) {
|
||||
if (!myLabeler.addMigrationRoot(method, valueType, myStatement, TypeConversionUtil.isAssignable(returnType, valueType) && !isGetter(value, method), true, true)
|
||||
&& TypeMigrationLabeler.typeContainsTypeParameters(returnType, Collections.<PsiTypeParameter>emptySet())) {
|
||||
&& TypeMigrationLabeler.typeContainsTypeParameters(returnType, Collections.emptySet())) {
|
||||
value.accept(this);
|
||||
}
|
||||
}
|
||||
@@ -638,7 +638,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor {
|
||||
PsiType type = myTypeEvaluator.evaluateType(expr);
|
||||
type = type instanceof PsiEllipsisType ? ((PsiEllipsisType)type).toArrayType() : type;
|
||||
myType = GenericsUtil.getVariableTypeByExpressionType(type);
|
||||
myChanged = (myOriginType == null || myType == null) ? false : !myType.equals(myOriginType);
|
||||
myChanged = !(myOriginType == null || myType == null) && !myType.equals(myOriginType);
|
||||
}
|
||||
|
||||
public TypeView(PsiVariable var, PsiSubstitutor varSubstitutor, PsiSubstitutor evalSubstitutor) {
|
||||
@@ -649,7 +649,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor {
|
||||
if (evalSubstitutor != null) realMap.putAll(evalSubstitutor.getSubstitutionMap());
|
||||
|
||||
myType = PsiSubstitutorImpl.createSubstitutor(realMap).substitute(myTypeEvaluator.getType(var));
|
||||
myChanged = (myOriginType == null || myType == null) ? false : !myType.equals(myOriginType);
|
||||
myChanged = !(myOriginType == null || myType == null) && !myType.equals(myOriginType);
|
||||
}
|
||||
|
||||
public PsiType getType() {
|
||||
|
||||
-6
@@ -34,12 +34,6 @@ public class ChangeTypeSignatureAction extends BaseRefactoringAction {
|
||||
}
|
||||
|
||||
public boolean isEnabledOnElements(@NotNull PsiElement[] elements) {
|
||||
Project currProject = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
|
||||
|
||||
if (currProject == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elements.length > 1) return false;
|
||||
|
||||
for (PsiElement element : elements) {
|
||||
|
||||
+2
-2
@@ -65,7 +65,7 @@ public class RootTypeConversionRule extends TypeConversionRule {
|
||||
if (Comparing.equal(functionalInterfaceType, to) && method.isEquivalentTo(LambdaUtil.getFunctionalInterfaceMethod(from))) {
|
||||
return new TypeConversionDescriptorBase() {
|
||||
@Override
|
||||
public PsiExpression replace(PsiExpression expression, TypeEvaluator evaluator) throws IncorrectOperationException {
|
||||
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException {
|
||||
final PsiMethodReferenceExpression methodReferenceExpression = (PsiMethodReferenceExpression)expression;
|
||||
final PsiExpression qualifierExpression = methodReferenceExpression.getQualifierExpression();
|
||||
if (qualifierExpression != null) {
|
||||
@@ -147,7 +147,7 @@ public class RootTypeConversionRule extends TypeConversionRule {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiExpression replace(PsiExpression expression, TypeEvaluator evaluator) throws IncorrectOperationException {
|
||||
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException {
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
|
||||
final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression();
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(expression.getProject());
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ public class FailedConversionsDialog extends DialogWrapper {
|
||||
panel.add(new JLabel(RefactoringBundle.message("the.following.problems.were.found")), BorderLayout.NORTH);
|
||||
panel.add(scrollPane, BorderLayout.CENTER);
|
||||
|
||||
@NonNls StringBuffer buf = new StringBuffer();
|
||||
@NonNls StringBuilder buf = new StringBuilder();
|
||||
for (String description : myConflictDescriptions) {
|
||||
buf.append(description);
|
||||
buf.append("<br><br>");
|
||||
|
||||
@@ -121,8 +121,4 @@ public class MigrationNode extends AbstractTreeNode<TypeMigrationUsageInfo> impl
|
||||
public MigrationNode getDuplicate() {
|
||||
return myDuplicatedNode;
|
||||
}
|
||||
|
||||
public boolean hasDuplicate() {
|
||||
return myDuplicatedNode != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,15 +187,14 @@ public class MigrationPanel extends JPanel implements Disposable {
|
||||
if (userObject instanceof MigrationRootNode) {
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
|
||||
final HashSet<VirtualFile> files = new HashSet<>();
|
||||
final TypeMigrationUsageInfo[] usages = ApplicationManager.getApplication().runReadAction(new Computable<TypeMigrationUsageInfo[]>() {
|
||||
@Override
|
||||
public TypeMigrationUsageInfo[] compute() {
|
||||
final TypeMigrationUsageInfo[] usages = ApplicationManager.getApplication().runReadAction(
|
||||
(Computable<TypeMigrationUsageInfo[]>)() -> {
|
||||
final Collection<? extends AbstractTreeNode> children = ((MigrationRootNode)userObject).getChildren();
|
||||
for (AbstractTreeNode child : children) {
|
||||
expandTree((MigrationNode)child);
|
||||
}
|
||||
final TypeMigrationUsageInfo[] usages = myLabeler.getMigratedUsages();
|
||||
for (TypeMigrationUsageInfo usage : usages) {
|
||||
final TypeMigrationUsageInfo[] usages1 = myLabeler.getMigratedUsages();
|
||||
for (TypeMigrationUsageInfo usage : usages1) {
|
||||
if (!usage.isExcluded()) {
|
||||
final PsiElement element = usage.getElement();
|
||||
if (element != null) {
|
||||
@@ -203,9 +202,8 @@ public class MigrationPanel extends JPanel implements Disposable {
|
||||
}
|
||||
}
|
||||
}
|
||||
return usages;
|
||||
}
|
||||
});
|
||||
return usages1;
|
||||
});
|
||||
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
@@ -306,7 +304,7 @@ public class MigrationPanel extends JPanel implements Disposable {
|
||||
}
|
||||
|
||||
public Object getData(@NonNls final String dataId) {
|
||||
if (DataConstants.PSI_ELEMENT.equals(dataId)) {
|
||||
if (CommonDataKeys.PSI_ELEMENT.is(dataId)) {
|
||||
final DefaultMutableTreeNode[] selectedNodes = getSelectedNodes(DefaultMutableTreeNode.class, null);
|
||||
return selectedNodes.length == 1 && selectedNodes[0].getUserObject() instanceof MigrationNode
|
||||
? ((MigrationNode)selectedNodes[0].getUserObject()).getInfo().getElement() : null;
|
||||
|
||||
@@ -37,7 +37,7 @@ import java.util.*;
|
||||
public class MigrationRootNode extends AbstractTreeNode<TypeMigrationLabeler> implements DuplicateNodeRenderer.DuplicatableNode {
|
||||
private final TypeMigrationLabeler myLabeler;
|
||||
private List<MigrationNode> myCachedChildren;
|
||||
private final PsiElement myRoots[];
|
||||
private final PsiElement[] myRoots;
|
||||
private final boolean myPreviewUsages;
|
||||
|
||||
protected MigrationRootNode(Project project,
|
||||
|
||||
+2
-2
@@ -22,10 +22,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @author anna
|
||||
* Date: 27-Mar-2008
|
||||
*/
|
||||
public class OverridenUsageInfo extends TypeMigrationUsageInfo {
|
||||
public class OverriddenUsageInfo extends TypeMigrationUsageInfo {
|
||||
private volatile String myMigrateMethodName;
|
||||
|
||||
public OverridenUsageInfo(@NotNull PsiElement element) {
|
||||
public OverriddenUsageInfo(@NotNull PsiElement element) {
|
||||
super(element);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.
|
||||
@@ -305,10 +305,6 @@ public class MethodCandidateInfo extends CandidateInfo{
|
||||
PsiSubstitutor substitutor = myCalcedSubstitutor;
|
||||
if (substitutor == null || !includeReturnConstraint && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) || isOverloadCheck()) {
|
||||
|
||||
if (includeReturnConstraint) {
|
||||
myInferenceError = null;
|
||||
}
|
||||
|
||||
PsiSubstitutor incompleteSubstitutor = super.getSubstitutor();
|
||||
PsiMethod method = getElement();
|
||||
if (myTypeArguments == null) {
|
||||
|
||||
@@ -29,7 +29,6 @@ import com.intellij.util.containers.IntArrayList;
|
||||
import com.intellij.util.containers.IntStack;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TIntArrayList;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -1330,30 +1329,47 @@ public class ControlFlowUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether variable can be referenced between start and stop points. Back-edges are also considered, so the actual place
|
||||
* where it referenced might be outside of (start, stop) interval.
|
||||
* Checks if the control flow instruction at given offset accesses (reads or writes) given variable
|
||||
*
|
||||
* @param flow ControlFlow to analyze
|
||||
* @param start start point
|
||||
* @param stop stop point
|
||||
* @param variable variable to analyze
|
||||
* @return true if variable can be referenced between start and stop points
|
||||
* @param flow control flow
|
||||
* @param offset offset inside given control flow
|
||||
* @param variable a variable the access to which is to be checked
|
||||
* @return true if the given instruction is actually a variable access
|
||||
*/
|
||||
public static boolean isVariableReferencedBetween(final ControlFlow flow,
|
||||
final int start,
|
||||
final int stop,
|
||||
final PsiVariable variable) {
|
||||
if(start == stop) return false;
|
||||
public static boolean isVariableAccess(ControlFlow flow, int offset, PsiVariable variable) {
|
||||
Instruction instruction = flow.getInstructions().get(offset);
|
||||
return instruction instanceof ReadVariableInstruction && ((ReadVariableInstruction)instruction).variable == variable ||
|
||||
instruction instanceof WriteVariableInstruction && ((WriteVariableInstruction)instruction).variable == variable;
|
||||
}
|
||||
|
||||
// DFS visits instructions mainly in backward direction while here visiting in forward direction
|
||||
// greatly reduces number of iterations. So first we just collect edges, then reverse their order.
|
||||
// contains (from, to) pairs representing control flow arcs
|
||||
final TIntArrayList list = new TIntArrayList();
|
||||
public static class ControlFlowEdge {
|
||||
public final int myFrom;
|
||||
public final int myTo;
|
||||
|
||||
public ControlFlowEdge(int from, int to) {
|
||||
myFrom = from;
|
||||
myTo = to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myFrom+"->"+myTo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns control flow edges which are potentially reachable from start instruction
|
||||
*
|
||||
* @param flow control flow to analyze
|
||||
* @param start starting instruction offset
|
||||
* @return a list of edges
|
||||
*/
|
||||
public static List<ControlFlowEdge> getEdges(ControlFlow flow, int start) {
|
||||
final List<ControlFlowEdge> list = new ArrayList<ControlFlowEdge>();
|
||||
depthFirstSearch(flow, new InstructionClientVisitor<Void>() {
|
||||
@Override
|
||||
public void visitInstruction(Instruction instruction, int offset, int nextOffset) {
|
||||
list.add(offset);
|
||||
list.add(nextOffset);
|
||||
list.add(new ControlFlowEdge(offset, nextOffset));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1361,34 +1377,7 @@ public class ControlFlowUtil {
|
||||
return null;
|
||||
}
|
||||
}, start, flow.getSize());
|
||||
BitSet violated = new BitSet();
|
||||
List<Instruction> instructions = flow.getInstructions();
|
||||
boolean changed = true;
|
||||
while(changed) {
|
||||
changed = false;
|
||||
for(int i=list.size()-2; i>=0; i-=2) {
|
||||
int from = list.get(i);
|
||||
int to = list.get(i+1);
|
||||
if(from == stop) continue;
|
||||
if(violated.get(from)) {
|
||||
if(!violated.get(to)) {
|
||||
if(to == stop) return true;
|
||||
violated.set(to);
|
||||
changed = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Instruction instruction = instructions.get(from);
|
||||
if((instruction instanceof ReadVariableInstruction && ((ReadVariableInstruction)instruction).variable == variable) ||
|
||||
(instruction instanceof WriteVariableInstruction && ((WriteVariableInstruction)instruction).variable == variable)) {
|
||||
violated.set(from);
|
||||
violated.set(to);
|
||||
if(to == stop) return true;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@ package com.intellij.psi.impl.source.resolve.graphInference;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.constraints.ExpressionCompatibilityConstraint;
|
||||
@@ -140,7 +141,7 @@ public class InferenceSessionContainer {
|
||||
final PsiSubstitutor partialSubstitutor,
|
||||
@NotNull final PsiCall parent,
|
||||
@NotNull final ParameterTypeInferencePolicy policy,
|
||||
final MethodCandidateInfo.CurrentCandidateProperties properties,
|
||||
@NotNull final MethodCandidateInfo.CurrentCandidateProperties properties,
|
||||
final InferenceSession parentSession) {
|
||||
final CompoundInitialState compoundInitialState = createState(parentSession);
|
||||
InitialInferenceState initialInferenceState = compoundInitialState.getInitialState(parent);
|
||||
@@ -148,6 +149,7 @@ public class InferenceSessionContainer {
|
||||
final InferenceSession childSession = new InferenceSession(initialInferenceState);
|
||||
final List<String> errorMessages = parentSession.getIncompatibleErrorMessages();
|
||||
if (errorMessages != null) {
|
||||
properties.getInfo().setInferenceError(StringUtil.join(errorMessages, "\n"));
|
||||
return childSession.prepareSubstitution();
|
||||
}
|
||||
return childSession.collectAdditionalAndInfer(parameters, arguments, properties, compoundInitialState.getInitialSubstitutor());
|
||||
|
||||
+2
-2
@@ -6,10 +6,10 @@ class Test {
|
||||
|
||||
Holder dataHolder = null;
|
||||
Result<String> r3 = new Result<error descr="Cannot infer arguments"><></error>(new Holder<>(dataHolder));
|
||||
Result<String> r4 = Result.create<error descr="'create(K)' in 'Result' cannot be applied to '(Holder)'">(new Holder<>(dataHolder))</error>;
|
||||
Result<String> r4 = Result.create(new Holder<error descr="Cannot infer arguments"><></error>(dataHolder));
|
||||
|
||||
Result<String> r5 = new Result<error descr="Cannot infer arguments"><></error>(Holder.create(dataHolder));
|
||||
Result<String> r6 = Result.create<error descr="'create(K)' in 'Result' cannot be applied to '(Holder)'">(Holder.create(dataHolder))</error>;
|
||||
Result<String> r6 = Result.create(Holder.create<error descr="'create(Holder<M>)' in 'Holder' cannot be applied to '(Holder)'">(dataHolder)</error>);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,6 +7,6 @@ class Test2 {
|
||||
}
|
||||
|
||||
{
|
||||
foo (bar(String.class), <error descr="'foo(java.lang.String, java.lang.Integer)' in 'Test2' cannot be applied to '(T, java.lang.String)'">""</error>);
|
||||
foo (bar<error descr="'bar(java.lang.Class<T>)' in 'Test2' cannot be applied to '(java.lang.Class<java.lang.String>)'">(String.class)</error>, "");
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -20,10 +20,10 @@ class TestIDEA128101 {
|
||||
|
||||
public static void test() {
|
||||
construct(String.class, createPath(integerAttribute), createPath(stringAttribute));
|
||||
construct1<error descr="'construct1(java.lang.Class<T>, TestIDEA128101.Path<K>...)' in 'TestIDEA128101' cannot be applied to '(java.lang.Class<java.lang.String>, TestIDEA128101.Path<Y>, TestIDEA128101.Path<java.lang.String>)'">(String.class, createPath(integerAttribute), createPath(stringAttribute))</error>;
|
||||
construct1(String.class, createPath<error descr="'createPath(TestIDEA128101.Attribute<Y>)' in 'TestIDEA128101' cannot be applied to '(TestIDEA128101.Attribute<java.lang.Integer>)'">(integerAttribute)</error>, createPath(stringAttribute));
|
||||
construct2(String.class, createPath(integerAttribute), createPath(stringAttribute));
|
||||
construct3<error descr="'construct3(java.lang.Class<java.lang.String>, TestIDEA128101.Path<? super K>...)' in 'TestIDEA128101' cannot be applied to '(java.lang.Class<java.lang.String>, TestIDEA128101.Path<Y>, TestIDEA128101.Path<Y>)'">(String.class, createPath(integerAttribute), createPath(stringAttribute))</error>;
|
||||
construct4<error descr="'construct4(java.lang.Class<java.lang.String>, TestIDEA128101.Path<? super K>, TestIDEA128101.Path<? super K>)' in 'TestIDEA128101' cannot be applied to '(java.lang.Class<java.lang.String>, TestIDEA128101.Path<Y>, TestIDEA128101.Path<Y>)'">(String.class, createPath(integerAttribute), createPath(stringAttribute))</error>;
|
||||
construct3(String.class, createPath<error descr="'createPath(TestIDEA128101.Attribute<Y>)' in 'TestIDEA128101' cannot be applied to '(TestIDEA128101.Attribute<java.lang.Integer>)'">(integerAttribute)</error>, createPath<error descr="'createPath(TestIDEA128101.Attribute<Y>)' in 'TestIDEA128101' cannot be applied to '(TestIDEA128101.Attribute<java.lang.String>)'">(stringAttribute)</error>);
|
||||
construct4(String.class, createPath<error descr="'createPath(TestIDEA128101.Attribute<Y>)' in 'TestIDEA128101' cannot be applied to '(TestIDEA128101.Attribute<java.lang.Integer>)'">(integerAttribute)</error>, createPath<error descr="'createPath(TestIDEA128101.Attribute<Y>)' in 'TestIDEA128101' cannot be applied to '(TestIDEA128101.Attribute<java.lang.String>)'">(stringAttribute)</error>);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -11,6 +11,6 @@ abstract class Overloadsss {
|
||||
|
||||
{
|
||||
List<String> l = foo(bar (null));
|
||||
List<String> l1 = foo(bar1<error descr="Ambiguous method call: both 'Overloadsss.bar1(List<K>)' and 'Overloadsss.bar1(Set<K>)' match">(null)</error>);
|
||||
List<String> l1 = foo(bar1<error descr="Ambiguous method call: both 'Overloadsss.bar1(List<Object>)' and 'Overloadsss.bar1(Set<Object>)' match">(null)</error>);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -8,8 +8,8 @@ class Test {
|
||||
IntStream mi = sp.map(Inner::foo);
|
||||
Stream<Integer> mI = sp.map(Inner::fooBoxed);
|
||||
|
||||
IntStream li = sp.<error descr="Ambiguous method call: both 'Stream.map(Function<? super Inner, ? extends R>)' and 'Stream.map(IntFunction<? super Inner>)' match">map</error>(inner->inner.<error descr="Cannot resolve method 'foo()'">foo</error>());
|
||||
Stream<Integer> lI = sp.<error descr="Ambiguous method call: both 'Stream.map(Function<? super Inner, ? extends R>)' and 'Stream.map(IntFunction<? super Inner>)' match">map</error>(inner -> inner.<error descr="Cannot resolve method 'fooBoxed()'">fooBoxed</error>());
|
||||
IntStream li = sp.<error descr="Ambiguous method call: both 'Stream.map(Function<? super Inner, ?>)' and 'Stream.map(IntFunction<? super Inner>)' match">map</error>(inner->inner.<error descr="Cannot resolve method 'foo()'">foo</error>());
|
||||
Stream<Integer> lI = sp.<error descr="Ambiguous method call: both 'Stream.map(Function<? super Inner, ?>)' and 'Stream.map(IntFunction<? super Inner>)' match">map</error>(inner -> inner.<error descr="Cannot resolve method 'fooBoxed()'">fooBoxed</error>());
|
||||
}
|
||||
|
||||
interface Stream<T> {
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
class IntStream {
|
||||
private void foo(IntStream s) {
|
||||
s.<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Integer>)' match">map</error>(i -> 1 << i);
|
||||
s.<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Integer>)' match">map</error>(i -> 1);
|
||||
s.<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Integer>)' match">map</error>(i -> i);
|
||||
s.<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Object>)' match">map</error>(i -> 1 << i);
|
||||
s.<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Object>)' match">map</error>(i -> 1);
|
||||
s.<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Object>)' match">map</error>(i -> i);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ class ReturnTypeIncompatibility {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
<error descr="Ambiguous method call: both 'ReturnTypeIncompatibility.call(I1<Integer>)' and 'ReturnTypeIncompatibility.call(I2<P>)' match">call</error>(i-> {return i;});
|
||||
<error descr="Ambiguous method call: both 'ReturnTypeIncompatibility.call(I1<Number>)' and 'ReturnTypeIncompatibility.call(I2<String>)' match">call</error>(i-> {return i;});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import java.util.function.Supplier;
|
||||
class Test {
|
||||
|
||||
public static void main(String... args) {
|
||||
<error descr="Ambiguous method call: both 'Test.c(Supplier<Integer>, Supplier<Integer>)' and 'Test.c(Supplier<T>, T)' match">c</error>(() -> 3, () -> 10);
|
||||
<error descr="Ambiguous method call: both 'Test.c(Supplier<Integer>, Supplier<Integer>)' and 'Test.c(Supplier<Integer>, Integer)' match">c</error>(() -> 3, () -> 10);
|
||||
}
|
||||
|
||||
public static <T> void c(Supplier<T> s1, Supplier<T> s2) {}
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ class Test1 {
|
||||
}
|
||||
|
||||
{
|
||||
bar(l -> <error descr="Unhandled exception: Test1.MyEx">baz(l)</error>);
|
||||
bar(l -> baz<error descr="'baz(T)' in 'Test1' cannot be applied to '(java.lang.Object)'">(l)</error>);
|
||||
bar(<error descr="Unhandled exception: Test1.MyEx">this::baz</error>);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -26,6 +26,6 @@ class Test {
|
||||
.map(object -> Arrays.stream(functions)
|
||||
.map(fn -> fn.apply(object))
|
||||
.collect(toList()))
|
||||
.collect<error descr="'collect(java.util.stream.Collector<? super java.util.List<capture<?>>,A,R>)' in 'java.util.stream.Stream' cannot be applied to '(java.util.stream.Collector<T,capture<?>,java.util.List<T>>)'">(toList())</error>;
|
||||
.collect(toList<error descr="'toList()' in 'java.util.stream.Collectors' cannot be applied to '()'">()</error>);
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -9,10 +9,7 @@ class Test {
|
||||
|
||||
<R> SuperFoo<R> foo(I<R> ax) { return null; }
|
||||
|
||||
SuperFoo<String> ls = foo(<error descr="no instance(s) of type variable(s) exist so that String conforms to Number
|
||||
inference variable R has incompatible bounds:
|
||||
equality constraints: String
|
||||
upper bounds: Object, Number">() -> new Foo<>()</error>);
|
||||
SuperFoo<String> ls = foo(() -> new Foo<error descr="Cannot infer arguments"><></error>());
|
||||
SuperFoo<Integer> li = foo(() -> new Foo<>());
|
||||
SuperFoo<?> lw = foo(() -> new Foo<>());
|
||||
}
|
||||
+4
-4
@@ -31,8 +31,8 @@ class Test {
|
||||
String i1 = instanceCall(this::m0);
|
||||
String i2 = instanceCall(this::m1);
|
||||
String i3 = instanceCall(this::m2);
|
||||
String i4 = instanceCall<error descr="Ambiguous method call: both 'Test.instanceCall(I0)' and 'Test.instanceCall(I1<String>)' match">(this::m01)</error>;
|
||||
String i5 = instanceCall<error descr="Ambiguous method call: both 'Test.instanceCall(I0)' and 'Test.instanceCall(I1<String>)' match">(this::m012)</error>;
|
||||
String i4 = instanceCall<error descr="Ambiguous method call: both 'Test.instanceCall(I0)' and 'Test.instanceCall(I1<Object>)' match">(this::m01)</error>;
|
||||
String i5 = instanceCall<error descr="Ambiguous method call: both 'Test.instanceCall(I0)' and 'Test.instanceCall(I1<Object>)' match">(this::m012)</error>;
|
||||
}
|
||||
|
||||
void n0() { }
|
||||
@@ -53,7 +53,7 @@ class Test {
|
||||
Test s1 = staticCall(Test::n0);
|
||||
Test s2 = staticCall(Test::n1);
|
||||
Test s3 = staticCall<error descr="Cannot resolve method 'staticCall(<method reference>)'">(Test::n2)</error>;
|
||||
Test s4 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Test>)' and 'Test.staticCall(I2<Test, String>)' match">(Test::n01)</error>;
|
||||
Test s5 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Test>)' and 'Test.staticCall(I2<Test, String>)' match">(Test::n012)</error>;
|
||||
Test s4 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Object>)' and 'Test.staticCall(I2<Object, String>)' match">(Test::n01)</error>;
|
||||
Test s5 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Object>)' and 'Test.staticCall(I2<Object, String>)' match">(Test::n012)</error>;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -34,7 +34,7 @@ class Test {
|
||||
{
|
||||
Set<String> m = replyWith(this::query);
|
||||
System.out.println(m);
|
||||
Set<String> m1 = replyWith<error descr="Ambiguous method call: both 'Test.replyWith(Function<String, List<String>>)' and 'Test.replyWith(Callable<List<String>>)' match">(this::query1)</error>;
|
||||
Set<String> m1 = replyWith<error descr="Ambiguous method call: both 'Test.replyWith(Function<Object, List<Object>>)' and 'Test.replyWith(Callable<List<Object>>)' match">(this::query1)</error>;
|
||||
System.out.println(m1);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,6 +4,6 @@ import java.util.Comparator;
|
||||
|
||||
class Main {
|
||||
public void test() {
|
||||
Collections.sort(new ArrayList<>(), <error descr="Non-static method cannot be referenced from a static context">Comparator::reversed</error>);
|
||||
Collections.sort(new ArrayList<error descr="Cannot infer arguments"><></error>(), <error descr="Non-static method cannot be referenced from a static context">Comparator::reversed</error>);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -14,6 +14,6 @@ class Main {
|
||||
}
|
||||
|
||||
{
|
||||
<error descr="Ambiguous method call: both 'Main.perform(Runnable)' and 'Main.perform(TRunnable<RuntimeException>)' match">perform</error>(() -> {});
|
||||
<error descr="Ambiguous method call: both 'Main.perform(Runnable)' and 'Main.perform(TRunnable<Throwable>)' match">perform</error>(() -> {});
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// "Replace with collect" "true"
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
List<String> test(BufferedReader br) throws IOException {
|
||||
List<String> result;
|
||||
result = br.lines().map(String::trim).collect(Collectors.toList());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// "Replace with collect" "true"
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
List<String> test(List<BufferedReader> readers) throws IOException {
|
||||
for(BufferedReader br : readers) {
|
||||
List<String> result;
|
||||
result = br.lines().map(String::trim).collect(Collectors.toList());
|
||||
if(result.size() > 10) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Replace with sum()" "true"
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Main {
|
||||
void test(BufferedReader br) throws IOException {
|
||||
long count = br.lines().map(String::trim).mapToLong(String::length).sum();
|
||||
System.out.println(count);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Replace with sum()" "true"
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Main {
|
||||
void test(BufferedReader br) throws IOException {
|
||||
long count = br.lines().map(String::trim).mapToLong(String::length).sum();
|
||||
System.out.println(count);
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Replace with collect" "true"
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public void test(Map<String, String[]> map) {
|
||||
List<String> result = map.entrySet().stream().filter(entry -> entry.getKey().startsWith("x")).map(Map.Entry::getValue).flatMap(Arrays::stream).map(String::trim).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// "Replace with collect" "true"
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
List<String> test(BufferedReader br) throws IOException {
|
||||
List<String> result = new ArrayList<>();
|
||||
String line = "";
|
||||
wh<caret>ile(null != (line = br.readLine())) {
|
||||
result.add(line.trim());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// "Replace with collect" "false"
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
List<String> test(List<BufferedReader> readers) throws IOException {
|
||||
List<String> result = new ArrayList<>();
|
||||
for(BufferedReader br : readers) {
|
||||
String line = "";
|
||||
wh<caret>ile (null != (line = br.readLine())) {
|
||||
result.add(line.trim());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// "Replace with collect" "true"
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
List<String> test(List<BufferedReader> readers) throws IOException {
|
||||
for(BufferedReader br : readers) {
|
||||
List<String> result = new ArrayList<>();
|
||||
String line = "";
|
||||
wh<caret>ile (null != (line = br.readLine())) {
|
||||
result.add(line.trim());
|
||||
}
|
||||
if(result.size() > 10) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// "Replace with sum()" "false"
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Main {
|
||||
void test(BufferedReader br) throws IOException {
|
||||
String line = "";
|
||||
long count = 0;
|
||||
wh<caret>ile((line = br.readLine()) != null) {
|
||||
count+=(line = line.trim()).length();
|
||||
}
|
||||
System.out.println(count);
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with sum()" "true"
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Main {
|
||||
void test(BufferedReader br) throws IOException {
|
||||
String line = "";
|
||||
long count = 0;
|
||||
wh<caret>ile((line = br.readLine()) != null) {
|
||||
line = line.trim();
|
||||
count+=line.length();
|
||||
}
|
||||
System.out.println(count);
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with sum()" "true"
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Main {
|
||||
void test(BufferedReader br) throws IOException {
|
||||
String line = "";
|
||||
long count = 0;
|
||||
wh<caret>ile((line = br.readLine()) != null) {
|
||||
String trimmed = line.trim();
|
||||
count+=trimmed.length();
|
||||
}
|
||||
System.out.println(count);
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with sum()" "false"
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Main {
|
||||
void test(BufferedReader br) throws IOException {
|
||||
String line = "";
|
||||
long count = 0;
|
||||
wh<caret>ile((line = br.readLine()) != null) {
|
||||
String trimmed = line.trim();
|
||||
count+=trimmed.length();
|
||||
}
|
||||
System.out.println(count+":"+line);
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// "Replace with collect" "true"
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Main {
|
||||
public void test(Map<String, String[]> map) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for(Map.Entry<String, String[]> entry: m<caret>ap.entrySet()) {
|
||||
if(entry.getKey().startsWith("x")) {
|
||||
String[] arr = entry.getValue();
|
||||
for (String str : arr) {
|
||||
str = str.trim();
|
||||
result.add(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Test {
|
||||
{
|
||||
String <caret>s = "hello";
|
||||
Runnable r = () -> {Runnable rr = () -> System.out.println(s);};
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class Test {
|
||||
{
|
||||
Runnable r = () -> {Runnable rr = () -> System.out.println("hello");};
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
class Foo {
|
||||
void foo(String[] input) {
|
||||
int temp = input.length;
|
||||
char[][] board = new char[temp][];
|
||||
for (int i = 0; i < temp; i++) {
|
||||
System.out.println(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class Foo {
|
||||
void foo(String[] input) {
|
||||
char[][] board = new char[input.length][];
|
||||
for (int i = 0; i < input.length; i++) {
|
||||
System.out.println(<selection>input.length</selection>);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.
|
||||
@@ -207,6 +207,10 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
|
||||
doTest(new MockIntroduceVariableHandler("temp", true, false, false, "int"));
|
||||
}
|
||||
|
||||
public void testInsideForLoopIndependantFromLoopVariable() {
|
||||
doTest(new MockIntroduceVariableHandler("temp", true, false, false, "int"));
|
||||
}
|
||||
|
||||
public void testDuplicateGenericExpressions() {
|
||||
doTest(new MockIntroduceVariableHandler("temp", true, false, false, "Foo2<? extends java.lang.Runnable>"));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -292,6 +292,10 @@ public class InlineLocalTest extends LightCodeInsightTestCase {
|
||||
"Variable 'hello' is accessed for writing");
|
||||
}
|
||||
|
||||
public void testInlineVariableIntoNestedLambda() throws Exception {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
public void testAvoidTypeSpecificationWhenPossibleToAvoid() throws Exception {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
+8
-10
@@ -42,11 +42,7 @@ public class BackwardReferenceIndexBuilder extends ModuleLevelBuilder {
|
||||
|
||||
@Override
|
||||
public void buildFinished(CompileContext context) {
|
||||
final BackwardReferenceIndexWriter writer = BackwardReferenceIndexWriter.getInstance();
|
||||
if (writer != null) {
|
||||
writer.close();
|
||||
}
|
||||
BackwardReferenceIndexWriter.clearInstance();
|
||||
BackwardReferenceIndexWriter.closeIfNeed();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,11 +50,13 @@ public class BackwardReferenceIndexBuilder extends ModuleLevelBuilder {
|
||||
ModuleChunk chunk,
|
||||
DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder,
|
||||
OutputConsumer outputConsumer) throws ProjectBuildException, IOException {
|
||||
final BackwardReferenceIndexWriter writer = BackwardReferenceIndexWriter.getInstance();
|
||||
if (writer != null) {
|
||||
for (ModuleBuildTarget target : chunk.getTargets()) {
|
||||
final Collection<String> files = dirtyFilesHolder.getRemovedFiles(target);
|
||||
writer.processDeletedFiles(files);
|
||||
if (dirtyFilesHolder.hasRemovedFiles()) {
|
||||
final BackwardReferenceIndexWriter writer = BackwardReferenceIndexWriter.getInstance();
|
||||
if (writer != null) {
|
||||
for (ModuleBuildTarget target : chunk.getTargets()) {
|
||||
final Collection<String> files = dirtyFilesHolder.getRemovedFiles(target);
|
||||
writer.processDeletedFiles(files);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
+28
-11
@@ -34,17 +34,12 @@ import org.jetbrains.jps.model.java.compiler.JavaCompilers;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static com.sun.tools.javac.code.Flags.PRIVATE;
|
||||
|
||||
public class BackwardReferenceIndexWriter {
|
||||
public static final String PROP_KEY = "ref.index.builder";
|
||||
|
||||
public static volatile boolean forceEnabled;
|
||||
public static final String PROP_KEY = "jps.backward.ref.index.builder";
|
||||
|
||||
private static volatile BackwardReferenceIndexWriter ourInstance;
|
||||
|
||||
@@ -56,8 +51,14 @@ public class BackwardReferenceIndexWriter {
|
||||
myRebuild = rebuild;
|
||||
}
|
||||
|
||||
public static void clearInstance() {
|
||||
ourInstance = null;
|
||||
public static void closeIfNeed() {
|
||||
if (ourInstance != null) {
|
||||
try {
|
||||
ourInstance.close();
|
||||
} finally {
|
||||
ourInstance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BackwardReferenceIndexWriter getInstance() {
|
||||
@@ -88,7 +89,7 @@ public class BackwardReferenceIndexWriter {
|
||||
}
|
||||
|
||||
public static boolean isEnabled() {
|
||||
return SystemProperties.getBooleanProperty(PROP_KEY, false) || forceEnabled;
|
||||
return SystemProperties.getBooleanProperty(PROP_KEY, false);
|
||||
}
|
||||
|
||||
void close() {
|
||||
@@ -213,7 +214,23 @@ public class BackwardReferenceIndexWriter {
|
||||
|
||||
private void updateHierarchyIndicesIncrementally(final CompilerBackwardReferenceIndex.LightDefinition classId, LightRef.JavaLightClassRef[] superIds) {
|
||||
final Collection<LightRef> rawOldSupers = myIndex.getHierarchyMap().get(classId);
|
||||
Set<LightRef> oldSuperClasses = rawOldSupers == null ? null : new THashSet<LightRef>(rawOldSupers);
|
||||
Set<LightRef> oldSuperClasses;
|
||||
if (rawOldSupers == null) {
|
||||
oldSuperClasses = null;
|
||||
}
|
||||
else {
|
||||
if (superIds.length == rawOldSupers.size()) {
|
||||
boolean needUpdate = false;
|
||||
for (LightRef.JavaLightClassRef id : superIds) {
|
||||
if (!rawOldSupers.contains(id)) {
|
||||
needUpdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!needUpdate) return;
|
||||
}
|
||||
oldSuperClasses = new THashSet<LightRef>(rawOldSupers);
|
||||
}
|
||||
for (LightRef.JavaLightClassRef superId: superIds) {
|
||||
if (oldSuperClasses == null || !oldSuperClasses.remove(superId)) {
|
||||
myIndex.getBackwardHierarchyMap().put(superId, classId);
|
||||
|
||||
@@ -31,16 +31,13 @@ import java.io.File
|
||||
|
||||
abstract class ReferenceIndexTestBase : JpsBuildTestCase() {
|
||||
public override fun setUp() {
|
||||
BackwardReferenceIndexWriter.forceEnabled = true
|
||||
super.setUp()
|
||||
// System.setProperty(BackwardReferenceIndexWriter.PROP_KEY, true.toString())
|
||||
System.setProperty(BackwardReferenceIndexWriter.PROP_KEY, true.toString())
|
||||
}
|
||||
|
||||
public override fun tearDown() {
|
||||
super.tearDown()
|
||||
BackwardReferenceIndexWriter.forceEnabled = false
|
||||
BackwardReferenceIndexWriter.clearInstance()
|
||||
// System.clearProperty(BackwardReferenceIndexWriter.PROP_KEY)
|
||||
System.clearProperty(BackwardReferenceIndexWriter.PROP_KEY)
|
||||
}
|
||||
|
||||
protected fun assertIndexOnRebuild(vararg files: String) {
|
||||
|
||||
@@ -38,9 +38,4 @@ public abstract class DocumentRunnable implements Runnable {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
public abstract static class IgnoreDocumentRunnable extends DocumentRunnable {
|
||||
public IgnoreDocumentRunnable() {
|
||||
super(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,12 @@ public class UsageInfo {
|
||||
|
||||
public UsageInfo(@NotNull PsiReference reference) {
|
||||
this(reference.getElement(), reference.getRangeInElement().getStartOffset(), reference.getRangeInElement().getEndOffset());
|
||||
myDynamicUsage = reference.resolve() == null;
|
||||
if (reference instanceof PsiPolyVariantReference) {
|
||||
myDynamicUsage = ((PsiPolyVariantReference)reference).multiResolve(false).length == 0;
|
||||
}
|
||||
else {
|
||||
myDynamicUsage = reference.resolve() == null;
|
||||
}
|
||||
}
|
||||
|
||||
public UsageInfo(@NotNull PsiQualifiedReferenceElement reference) {
|
||||
|
||||
@@ -48,9 +48,7 @@ public class ZipHandler extends ArchiveHandler {
|
||||
@Override
|
||||
protected ZipFile createAccessor(ZipHandler key) throws IOException {
|
||||
final String canonicalPathToZip = key.getCanonicalPathToZip();
|
||||
FileAttributes attributes = FileSystemUtil.getAttributes(canonicalPathToZip);
|
||||
key.myFileStamp = attributes != null ? attributes.lastModified : DEFAULT_TIMESTAMP;
|
||||
key.myFileLength = attributes != null ? attributes.length : DEFAULT_LENGTH;
|
||||
setFileStampAndLength(key, canonicalPathToZip);
|
||||
|
||||
return new ZipFile(canonicalPathToZip);
|
||||
}
|
||||
@@ -67,6 +65,13 @@ public class ZipHandler extends ArchiveHandler {
|
||||
}
|
||||
};
|
||||
|
||||
private static synchronized void setFileStampAndLength(ZipHandler zipHandler, String pathToZip) {
|
||||
FileAttributes attributes = FileSystemUtil.getAttributes(pathToZip);
|
||||
|
||||
zipHandler.myFileStamp = attributes != null ? attributes.lastModified : DEFAULT_TIMESTAMP;
|
||||
zipHandler.myFileLength = attributes != null ? attributes.length : DEFAULT_LENGTH;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getCanonicalPathToZip() throws IOException {
|
||||
String value = myCanonicalPathToZip;
|
||||
@@ -79,30 +84,52 @@ public class ZipHandler extends ArchiveHandler {
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<String, EntryInfo> createEntriesMap() throws IOException {
|
||||
FileAccessorCache.Handle<ZipFile> zipRef = getZipFileHandle();
|
||||
try {
|
||||
ZipFile zip = zipRef.get();
|
||||
FileAccessorCache.Handle<ZipFile> existingZipRef = getZipHandleForIteratingEntries();
|
||||
|
||||
Map<String, EntryInfo> map = new ZipEntryMap(zip.size());
|
||||
map.put("", createRootEntry());
|
||||
if (existingZipRef == null) {
|
||||
File file = getFile();
|
||||
ZipFile zipFile = new ZipFile(file);
|
||||
|
||||
Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
getOrCreate(entries.nextElement(), map, zip);
|
||||
setFileStampAndLength(this, file.getPath());
|
||||
try {
|
||||
return buildEntryMapForZipFile(zipFile);
|
||||
}
|
||||
finally {
|
||||
zipFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
try {
|
||||
return buildEntryMapForZipFile(existingZipRef.get());
|
||||
}
|
||||
finally {
|
||||
zipRef.release();
|
||||
existingZipRef.release();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private FileAccessorCache.Handle<ZipFile> getZipFileHandle() throws IOException {
|
||||
FileAccessorCache.Handle<ZipFile> handle = ourZipFileFileAccessorCache.get(this);
|
||||
protected @Nullable FileAccessorCache.Handle<ZipFile> getZipHandleForIteratingEntries() throws IOException {
|
||||
return getCachedZipFileHandle(true);
|
||||
}
|
||||
|
||||
if (getFile() == getFileToUse()) { // files are canonicalized
|
||||
@NotNull
|
||||
private Map<String, EntryInfo> buildEntryMapForZipFile(ZipFile zip) {
|
||||
Map<String, EntryInfo> map = new ZipEntryMap(zip.size());
|
||||
map.put("", createRootEntry());
|
||||
|
||||
Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
getOrCreate(entries.nextElement(), map, zip);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected FileAccessorCache.Handle<ZipFile> getCachedZipFileHandle(boolean createHandleIfNeeded) throws IOException {
|
||||
FileAccessorCache.Handle<ZipFile> handle = createHandleIfNeeded ? ourZipFileFileAccessorCache.get(this) : ourZipFileFileAccessorCache.getIfCached(this);
|
||||
|
||||
// check handle is valid
|
||||
if (handle != null && getFile() == getFileToUse()) { // files are canonicalized
|
||||
// IDEA-148458, http://bugs.java.com/view_bug.do?bug_id=4425695, JVM crashes on use of opened ZipFile after it was updated
|
||||
// Reopen file if the file has been changed
|
||||
FileAttributes attributes = FileSystemUtil.getAttributes(getCanonicalPathToZip());
|
||||
@@ -200,7 +227,7 @@ public class ZipHandler extends ArchiveHandler {
|
||||
FileAccessorCache.Handle<ZipFile> zipRef;
|
||||
|
||||
try {
|
||||
zipRef = getZipFileHandle();
|
||||
zipRef = getCachedZipFileHandle(true);
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
Throwable cause = ex.getCause();
|
||||
|
||||
@@ -41,7 +41,7 @@ internal class KeePassCredentialStore(keyToValue: Map<CredentialAttributes, Cred
|
||||
baseDirectory: Path = Paths.get(PathManager.getConfigPath()),
|
||||
var memoryOnly: Boolean = false,
|
||||
private val dbFile: Path = baseDirectory.resolve(DB_FILE_NAME),
|
||||
existingMasterPassword: String? = null) : PasswordStorage, CredentialStore {
|
||||
existingMasterPassword: ByteArray? = null) : PasswordStorage, CredentialStore {
|
||||
private val db: KeePassDatabase
|
||||
|
||||
private val masterKeyStorage = MasterKeyFileStorage(baseDirectory)
|
||||
@@ -52,7 +52,7 @@ internal class KeePassCredentialStore(keyToValue: Map<CredentialAttributes, Cred
|
||||
if (keyToValue == null) {
|
||||
needToSave = AtomicBoolean(false)
|
||||
|
||||
val masterPassword = existingMasterPassword?.toByteArray() ?: masterKeyStorage.get()
|
||||
val masterPassword = existingMasterPassword ?: masterKeyStorage.get()
|
||||
if (masterPassword == null) {
|
||||
LOG.catchAndLog {
|
||||
if (dbFile.exists()) {
|
||||
@@ -66,7 +66,7 @@ internal class KeePassCredentialStore(keyToValue: Map<CredentialAttributes, Cred
|
||||
else {
|
||||
db = loadKdbx(dbFile, KdbxPassword(masterPassword)) ?: KeePassDatabase()
|
||||
if (existingMasterPassword != null) {
|
||||
masterKeyStorage.set(existingMasterPassword.toByteArray())
|
||||
masterKeyStorage.set(existingMasterPassword)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,12 +178,11 @@ internal class KeePassCredentialStore(keyToValue: Map<CredentialAttributes, Cred
|
||||
}
|
||||
}
|
||||
|
||||
fun setMasterPassword(password: String) {
|
||||
fun setMasterPassword(masterPassword: ByteArray) {
|
||||
LOG.assertTrue(!memoryOnly)
|
||||
|
||||
val masterKey = password.toByteArray()
|
||||
masterKeyStorage.set(masterKey)
|
||||
dbFile.writeSafe { db.save(KdbxPassword(masterKey), it) }
|
||||
masterKeyStorage.set(masterPassword)
|
||||
dbFile.writeSafe { db.save(KdbxPassword(masterPassword), it) }
|
||||
dbFile.setOwnerPermissions()
|
||||
}
|
||||
}
|
||||
@@ -192,7 +191,7 @@ internal fun copyFileDatabase(path: Path, masterPassword: String, baseDirectory:
|
||||
val dbFile = baseDirectory.resolve(DB_FILE_NAME)
|
||||
Files.copy(path, dbFile, StandardCopyOption.REPLACE_EXISTING)
|
||||
dbFile.setOwnerPermissions()
|
||||
return KeePassCredentialStore(baseDirectory = baseDirectory, dbFile = dbFile, existingMasterPassword = masterPassword)
|
||||
return KeePassCredentialStore(baseDirectory = baseDirectory, dbFile = dbFile, existingMasterPassword = masterPassword.toByteArray())
|
||||
}
|
||||
|
||||
internal fun copyTo(from: Map<CredentialAttributes, Credentials>, store: PasswordStorage) {
|
||||
|
||||
@@ -15,16 +15,20 @@
|
||||
*/
|
||||
package com.intellij.credentialStore
|
||||
|
||||
import com.intellij.credentialStore.PasswordSafeSettings.ProviderType
|
||||
import com.intellij.ide.passwordSafe.PasswordSafe
|
||||
import com.intellij.ide.passwordSafe.impl.PasswordSafeImpl
|
||||
import com.intellij.ide.passwordSafe.impl.createPersistentCredentialStore
|
||||
import com.intellij.openapi.options.ConfigurableBase
|
||||
import com.intellij.openapi.options.ConfigurableUi
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.ui.components.JBPasswordField
|
||||
import com.intellij.ui.components.RadioButton
|
||||
import com.intellij.ui.layout.*
|
||||
import com.intellij.util.text.nullize
|
||||
import gnu.trove.THashMap
|
||||
import java.awt.Component
|
||||
import javax.swing.JPanel
|
||||
|
||||
class PasswordSafeConfigurable(private val settings: PasswordSafeSettings) : ConfigurableBase<PasswordSafeConfigurableUi, PasswordSafeSettings>("application.passwordSafe", "Passwords", "reference.ide.settings.password.safe") {
|
||||
override fun getSettings() = settings
|
||||
@@ -33,56 +37,139 @@ class PasswordSafeConfigurable(private val settings: PasswordSafeSettings) : Con
|
||||
}
|
||||
|
||||
class PasswordSafeConfigurableUi : ConfigurableUi<PasswordSafeSettings> {
|
||||
private val saveOnDisk = RadioButton("Save on &disk")
|
||||
private val rememberPasswordsUntilClosing = RadioButton("Remember passwords &until the application is closed")
|
||||
private val inKeychain = RadioButton("In Native Keychain")
|
||||
|
||||
private val inKeePass = RadioButton("In KeePass")
|
||||
private val keePassMasterPassword = JBPasswordField()
|
||||
|
||||
private val rememberPasswordsUntilClosing = RadioButton("Do not save, forget passwords after restart")
|
||||
|
||||
private val modeToRow = THashMap<ProviderType, Row>()
|
||||
|
||||
override fun reset(settings: PasswordSafeSettings) {
|
||||
when (settings.providerType) {
|
||||
ProviderType.MEMORY_ONLY -> rememberPasswordsUntilClosing.isSelected = true
|
||||
ProviderType.MASTER_PASSWORD -> saveOnDisk.isSelected = true
|
||||
ProviderType.KEYCHAIN -> inKeychain.isSelected = true
|
||||
ProviderType.KEEPASS -> inKeePass.isSelected = true
|
||||
else -> throw IllegalStateException("Unknown provider type: ${settings.providerType}")
|
||||
}
|
||||
|
||||
updateEnabledState()
|
||||
}
|
||||
|
||||
override fun isModified(settings: PasswordSafeSettings) = getProviderType() != settings.providerType
|
||||
override fun isModified(settings: PasswordSafeSettings): Boolean {
|
||||
if (getProviderType() != settings.providerType) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (getProviderType() == ProviderType.KEEPASS && String(keePassMasterPassword.password).nullize(true) != null) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun apply(settings: PasswordSafeSettings) {
|
||||
settings.providerType = getProviderType()
|
||||
val providerType = getProviderType()
|
||||
val passwordSafe = PasswordSafe.getInstance() as PasswordSafeImpl
|
||||
var provider = passwordSafe.currentProvider
|
||||
|
||||
val masterPassword = String(keePassMasterPassword.password).nullize(true)?.toByteArray()
|
||||
|
||||
if (settings.providerType != providerType) {
|
||||
@Suppress("NON_EXHAUSTIVE_WHEN")
|
||||
when (providerType) {
|
||||
ProviderType.MEMORY_ONLY -> {
|
||||
if (provider is KeePassCredentialStore) {
|
||||
provider.memoryOnly = true
|
||||
provider.deleteFileStorage()
|
||||
}
|
||||
else {
|
||||
provider = KeePassCredentialStore(memoryOnly = true)
|
||||
}
|
||||
}
|
||||
|
||||
ProviderType.KEYCHAIN -> {
|
||||
provider = createPersistentCredentialStore(provider as? KeePassCredentialStore)
|
||||
}
|
||||
|
||||
ProviderType.KEEPASS -> {
|
||||
provider = KeePassCredentialStore(memoryOnly = true, existingMasterPassword = masterPassword)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (providerType == ProviderType.KEEPASS) {
|
||||
if (provider === passwordSafe.currentProvider && masterPassword != null) {
|
||||
// so, provider is the same and we must change master password for existing database file
|
||||
(provider as KeePassCredentialStore).setMasterPassword(masterPassword)
|
||||
}
|
||||
}
|
||||
|
||||
settings.providerType = providerType
|
||||
}
|
||||
|
||||
override fun getComponent() = panel {
|
||||
val passwordSafe = PasswordSafe.getInstance() as PasswordSafeImpl
|
||||
fun updateEnabledState() {
|
||||
modeToRow[ProviderType.KEEPASS]?.enabled = getProviderType() == ProviderType.KEEPASS
|
||||
}
|
||||
|
||||
buttonGroup {
|
||||
row {
|
||||
saveOnDisk()
|
||||
if (!passwordSafe.isNativeCredentialStoreUsed) {
|
||||
button("Set Master Password") { event ->
|
||||
Messages.showInputDialog(event.source as Component, "Master Password:", "Set Master Password", null)?.trim().nullize()?.let {
|
||||
passwordSafe.setFileDatabaseMasterPassword(it)
|
||||
}
|
||||
override fun getComponent(): JPanel {
|
||||
val passwordSafe = PasswordSafe.getInstance() as PasswordSafeImpl
|
||||
val currentProvider = passwordSafe.currentProvider
|
||||
|
||||
keePassMasterPassword.setPasswordIsStored(true)
|
||||
|
||||
val panel = panel {
|
||||
row { label("Save passwords:") }
|
||||
|
||||
buttonGroup({ updateEnabledState() }) {
|
||||
if (SystemInfo.isLinux || isMacOsCredentialStoreSupported) {
|
||||
row {
|
||||
inKeychain()
|
||||
}
|
||||
}
|
||||
|
||||
row {
|
||||
inKeePass()
|
||||
|
||||
modeToRow[ProviderType.KEEPASS] = row("Master Password:") {
|
||||
keePassMasterPassword(growPolicy = GrowPolicy.SHORT_TEXT)
|
||||
}
|
||||
}
|
||||
|
||||
row {
|
||||
rememberPasswordsUntilClosing()
|
||||
}
|
||||
if (currentProvider is KeePassCredentialStore && !currentProvider.memoryOnly) {
|
||||
row { hint("Existing KeePass file will be removed.") }
|
||||
}
|
||||
}
|
||||
|
||||
if (!passwordSafe.isNativeCredentialStoreUsed) {
|
||||
row(separated = true) {
|
||||
button("Clear Passwords") { event ->
|
||||
passwordSafe.clearPasswords()
|
||||
Messages.showInfoMessage(event.source as Component, "Passwords were cleared", "Clear Passwords")
|
||||
}
|
||||
}
|
||||
}
|
||||
row { rememberPasswordsUntilClosing() }
|
||||
}
|
||||
|
||||
if (!passwordSafe.isNativeCredentialStoreUsed) {
|
||||
row(separated = true) {
|
||||
button("Clear Passwords") { event ->
|
||||
passwordSafe.clearPasswords()
|
||||
Messages.showInfoMessage(event.source as Component, "Passwords were cleared", "Clear Passwords")
|
||||
}
|
||||
}
|
||||
}
|
||||
return panel
|
||||
}
|
||||
|
||||
private fun getProviderType(): ProviderType {
|
||||
if (rememberPasswordsUntilClosing.isSelected) {
|
||||
return ProviderType.MEMORY_ONLY
|
||||
}
|
||||
else {
|
||||
return ProviderType.MASTER_PASSWORD
|
||||
return when {
|
||||
rememberPasswordsUntilClosing.isSelected -> ProviderType.MEMORY_ONLY
|
||||
inKeePass.isSelected -> ProviderType.KEEPASS
|
||||
else -> ProviderType.KEYCHAIN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal enum class ProviderType {
|
||||
MEMORY_ONLY, KEYCHAIN, KEEPASS,
|
||||
|
||||
// unused, but we cannot remove it because enum value maybe stored in the config and we must correctly deserialize it
|
||||
@Deprecated("")
|
||||
DO_NOT_STORE
|
||||
}
|
||||
@@ -18,7 +18,6 @@
|
||||
package com.intellij.ide.passwordSafe.impl
|
||||
|
||||
import com.intellij.credentialStore.*
|
||||
import com.intellij.credentialStore.PasswordSafeSettings.ProviderType
|
||||
import com.intellij.ide.passwordSafe.PasswordSafe
|
||||
import com.intellij.ide.passwordSafe.PasswordStorage
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
@@ -28,7 +27,7 @@ import org.jetbrains.concurrency.runAsync
|
||||
import java.nio.file.Path
|
||||
|
||||
class PasswordSafeImpl(/* public - backward compatibility */val settings: PasswordSafeSettings) : PasswordSafe(), SettingsSavingComponent {
|
||||
private @Volatile var currentProvider: PasswordStorage
|
||||
internal @Volatile var currentProvider: PasswordStorage
|
||||
|
||||
// it is helper storage to support set password as memory-only (see setPassword memoryOnly flag)
|
||||
private val memoryHelperProvider = lazy { KeePassCredentialStore(emptyMap(), memoryOnly = true) }
|
||||
@@ -45,25 +44,23 @@ class PasswordSafeImpl(/* public - backward compatibility */val settings: Passwo
|
||||
else {
|
||||
currentProvider = createPersistentCredentialStore()
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().messageBus.connect().subscribe(PasswordSafeSettings.TOPIC, object: PasswordSafeSettingsListener {
|
||||
override fun typeChanged(oldValue: ProviderType, newValue: ProviderType) {
|
||||
val memoryOnly = newValue == ProviderType.MEMORY_ONLY
|
||||
if (memoryOnly) {
|
||||
val provider = currentProvider
|
||||
if (provider is KeePassCredentialStore) {
|
||||
provider.memoryOnly = true
|
||||
provider.deleteFileStorage()
|
||||
}
|
||||
else {
|
||||
currentProvider = KeePassCredentialStore(memoryOnly = true)
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentProvider = createPersistentCredentialStore(currentProvider as? KeePassCredentialStore)
|
||||
}
|
||||
internal fun setProvider(type: ProviderType) {
|
||||
val memoryOnly = type == ProviderType.MEMORY_ONLY
|
||||
if (memoryOnly) {
|
||||
val provider = currentProvider
|
||||
if (provider is KeePassCredentialStore) {
|
||||
provider.memoryOnly = true
|
||||
provider.deleteFileStorage()
|
||||
}
|
||||
})
|
||||
else {
|
||||
currentProvider = KeePassCredentialStore(memoryOnly = true)
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentProvider = createPersistentCredentialStore(currentProvider as? KeePassCredentialStore)
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(attributes: CredentialAttributes): Credentials? {
|
||||
@@ -122,9 +119,7 @@ class PasswordSafeImpl(/* public - backward compatibility */val settings: Passwo
|
||||
ApplicationManager.getApplication().messageBus.syncPublisher(PasswordSafeSettings.TOPIC).credentialStoreCleared()
|
||||
}
|
||||
|
||||
fun setFileDatabaseMasterPassword(password: String) {
|
||||
(currentProvider as KeePassCredentialStore).setMasterPassword(password)
|
||||
}
|
||||
internal fun getKeePassCredentialStore() = currentProvider as KeePassCredentialStore
|
||||
|
||||
fun importFileDatabase(path: Path, masterPassword: String) {
|
||||
currentProvider = copyFileDatabase(path, masterPassword)
|
||||
@@ -157,7 +152,7 @@ class PasswordSafeImpl(/* public - backward compatibility */val settings: Passwo
|
||||
get() = memoryHelperProvider.value
|
||||
}
|
||||
|
||||
private fun createPersistentCredentialStore(existing: KeePassCredentialStore? = null, convertFileStore: Boolean = false): PasswordStorage {
|
||||
internal fun createPersistentCredentialStore(existing: KeePassCredentialStore? = null, convertFileStore: Boolean = false): PasswordStorage {
|
||||
LOG.catchAndLog {
|
||||
for (factory in CredentialStoreFactory.CREDENTIAL_STORE_FACTORY.extensions) {
|
||||
val store = factory.create() ?: continue
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class PasswordSafeSettings implements PersistentStateComponent<PasswordSafeSettings.State> {
|
||||
public static final Topic<PasswordSafeSettingsListener> TOPIC = Topic.create("PasswordSafeSettingsListener", PasswordSafeSettingsListener.class);
|
||||
|
||||
private ProviderType myProviderType = ProviderType.MASTER_PASSWORD;
|
||||
private ProviderType myProviderType = ProviderType.KEYCHAIN;
|
||||
|
||||
@NotNull
|
||||
public ProviderType getProviderType() {
|
||||
@@ -56,23 +56,10 @@ public class PasswordSafeSettings implements PersistentStateComponent<PasswordSa
|
||||
}
|
||||
|
||||
public void loadState(@NotNull State state) {
|
||||
setProviderType(ObjectUtils.chooseNotNull(state.PROVIDER, ProviderType.MASTER_PASSWORD));
|
||||
setProviderType(ObjectUtils.chooseNotNull(state.PROVIDER, ProviderType.KEYCHAIN));
|
||||
}
|
||||
|
||||
public static class State {
|
||||
public ProviderType PROVIDER = ProviderType.MASTER_PASSWORD;
|
||||
}
|
||||
|
||||
public enum ProviderType {
|
||||
@Deprecated
|
||||
DO_NOT_STORE,
|
||||
/**
|
||||
* The passwords are stored only in the memory
|
||||
*/
|
||||
MEMORY_ONLY,
|
||||
/**
|
||||
* The passwords are encrypted with master password
|
||||
*/
|
||||
MASTER_PASSWORD
|
||||
public ProviderType PROVIDER = ProviderType.KEYCHAIN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.intellij.credentialStore;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface PasswordSafeSettingsListener {
|
||||
default void typeChanged(@NotNull PasswordSafeSettings.ProviderType oldValue, @NotNull PasswordSafeSettings.ProviderType newValue) {
|
||||
default void typeChanged(@NotNull ProviderType oldValue, @NotNull ProviderType newValue) {
|
||||
}
|
||||
|
||||
default void credentialStoreCleared() {
|
||||
|
||||
@@ -112,7 +112,7 @@ internal class PasswordDatabaseConvertor : ApplicationLoadListener {
|
||||
val oldDbFile = Paths.get(PathManager.getConfigPath(), "options", "security.xml")
|
||||
if (oldDbFile.exists()) {
|
||||
val settings = ServiceManager.getService(PasswordSafeSettings::class.java)
|
||||
if (settings.providerType != PasswordSafeSettings.ProviderType.MASTER_PASSWORD) {
|
||||
if (settings.providerType != ProviderType.KEYCHAIN) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ class FileCredentialStoreTest {
|
||||
credentialMap.put(attributes, credentials)
|
||||
}
|
||||
|
||||
provider.setMasterPassword("foo")
|
||||
provider.setMasterPassword("foo".toByteArray())
|
||||
|
||||
val pdbFile = baseDir.resolve("c.kdbx")
|
||||
val pdbPwdFile = baseDir.resolve("pdb.pwd")
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.ide.BrowserUtil;
|
||||
import com.intellij.openapi.ui.popup.ComponentPopupBuilder;
|
||||
import com.intellij.openapi.ui.popup.JBPopup;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.vcs.history.VcsHistoryUtil;
|
||||
import com.intellij.ui.HyperlinkAdapter;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
@@ -51,7 +52,7 @@ public class VcsCommitInfoBalloon {
|
||||
myEditorPane.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
|
||||
myEditorPane.setEditable(false);
|
||||
myEditorPane.setBackground(HintUtil.INFORMATION_COLOR);
|
||||
myEditorPane.setFont(UIUtil.getToolTipFont());
|
||||
myEditorPane.setFont(VcsHistoryUtil.getCommitDetailsFont());
|
||||
myEditorPane.setBorder(HintUtil.createHintBorder());
|
||||
Border margin = IdeBorderFactory.createEmptyBorder(3, 3, 3, 3);
|
||||
myEditorPane.setBorder(new CompoundBorder(myEditorPane.getBorder(), margin));
|
||||
|
||||
@@ -15,13 +15,19 @@
|
||||
*/
|
||||
package com.intellij.dvcs.repo;
|
||||
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
* The listener interface for handling async vcs files holder events.
|
||||
* When a files holder model starts/finishes to update itself -> updateStarted/Finished will be called for all subscribers.
|
||||
* e.g. vcs updates its ignored file model after that we should trigger ui update in ChangesView;
|
||||
* <p>
|
||||
* The listener interface for handling async {@link ChangeListManager} node models updating.
|
||||
* </p>
|
||||
* <p>
|
||||
* When model starts/finishes to update itself -> updateStarted/Finished will be called for all subscribers.<br/>
|
||||
* e.g. vcs updates its ignored file model after that we should trigger ui update in ChangesView;<br/>
|
||||
* moreover, when long duration update starts we should also trigger some action;
|
||||
* </p>
|
||||
*/
|
||||
public interface AsyncFilesManagerListener extends EventListener {
|
||||
|
||||
|
||||
+22
-9
@@ -18,21 +18,34 @@ package com.intellij.codeInsight.hints
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.lang.LanguageExtension
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
object InlayParameterHintsExtension: LanguageExtension<InlayParameterHintsProvider>("com.intellij.parameterHintsProvider")
|
||||
|
||||
@ApiStatus.Experimental
|
||||
interface InlayParameterHintsProvider {
|
||||
|
||||
fun getParameterHints(element: PsiElement): List<InlayInfo> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
fun getMethodInfo(element: PsiElement): MethodInfo? {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Hints for params to be shown
|
||||
*/
|
||||
fun getParameterHints(element: PsiElement): List<InlayInfo> = emptyList()
|
||||
|
||||
/**
|
||||
* Provides fully qualified method name (e.g. "java.util.Map.put") and list of it's parameter names.
|
||||
* Used when adding method to blacklist, when user invokes alt-enter on hint
|
||||
* and selects "Do not show for this method".
|
||||
*/
|
||||
fun getMethodInfo(element: PsiElement): MethodInfo? = null
|
||||
|
||||
/**
|
||||
* Language used when saving blacklist methods
|
||||
* Maybe will be moved to MethodInfo
|
||||
*/
|
||||
val language: Language
|
||||
|
||||
|
||||
/**
|
||||
* Default list of methods for which hints should not be shown
|
||||
*/
|
||||
val defaultBlackList: Set<String>
|
||||
|
||||
}
|
||||
|
||||
@@ -173,7 +173,6 @@ public class DaemonListeners implements Disposable {
|
||||
// clearing highlighters before changing document because change can damage editor highlighters drastically, so we'll clear more than necessary
|
||||
@Override
|
||||
public void beforeDocumentChange(final DocumentEvent e) {
|
||||
if (isUnderIgnoredAction(null)) return;
|
||||
Document document = e.getDocument();
|
||||
VirtualFile virtualFile = fileDocumentManager.getFile(document);
|
||||
Project project = virtualFile == null ? null : ProjectUtil.guessProjectForFile(virtualFile);
|
||||
@@ -348,12 +347,6 @@ public class DaemonListeners implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isUnderIgnoredAction(@Nullable Object action) {
|
||||
return action instanceof DocumentRunnable.IgnoreDocumentRunnable ||
|
||||
action == DocumentRunnable.IgnoreDocumentRunnable.class ||
|
||||
ApplicationManager.getApplication().hasWriteAction(DocumentRunnable.IgnoreDocumentRunnable.class);
|
||||
}
|
||||
|
||||
private boolean worthBothering(final Document document, Project project) {
|
||||
if (document == null) return true;
|
||||
if (project != null && project != myProject) return false;
|
||||
@@ -432,7 +425,6 @@ public class DaemonListeners implements Disposable {
|
||||
@Override
|
||||
public void commandStarted(CommandEvent event) {
|
||||
Document affectedDocument = extractDocumentFromCommand(event);
|
||||
if (isUnderIgnoredAction(null)) return;
|
||||
if (!worthBothering(affectedDocument, event.getProject())) return;
|
||||
|
||||
cutOperationJustHappened = myCutActionName.equals(event.getCommandName());
|
||||
@@ -461,7 +453,6 @@ public class DaemonListeners implements Disposable {
|
||||
@Override
|
||||
public void commandFinished(CommandEvent event) {
|
||||
Document affectedDocument = extractDocumentFromCommand(event);
|
||||
if (isUnderIgnoredAction(null)) return;
|
||||
if (!worthBothering(affectedDocument, event.getProject())) return;
|
||||
|
||||
if (myEscPressed) {
|
||||
|
||||
@@ -104,7 +104,7 @@ class PsiChangeHandler extends PsiTreeChangeAdapter implements Disposable {
|
||||
|
||||
private void updateChangesForDocument(@NotNull final Document document) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
if (DaemonListeners.isUnderIgnoredAction(null) || myProject.isDisposed()) return;
|
||||
if (myProject.isDisposed()) return;
|
||||
List<Pair<PsiElement, Boolean>> toUpdate = changedElements.get(document);
|
||||
if (toUpdate == null) {
|
||||
// The document has been changed, but psi hasn't
|
||||
|
||||
@@ -22,13 +22,12 @@ import com.intellij.codeInsight.hints.settings.ParameterNameHintsConfigurable
|
||||
import com.intellij.codeInsight.hints.settings.ParameterNameHintsSettings
|
||||
import com.intellij.codeInsight.intention.HighPriorityAction
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.injected.editor.EditorWindow
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.InlayModel
|
||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
|
||||
import com.intellij.openapi.editor.impl.InlayModelImpl
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.ProjectManager
|
||||
@@ -119,7 +118,7 @@ class ToggleInlineHintsAction : AnAction() {
|
||||
}
|
||||
|
||||
private fun hasParameterHintAtOffset(editor: Editor, file: PsiFile): Boolean {
|
||||
if (editor.inlayModel !is InlayModel) return false
|
||||
if (editor is EditorWindow) return false
|
||||
|
||||
val offset = editor.caretModel.offset
|
||||
val element = file.findElementAt(offset)
|
||||
@@ -127,7 +126,7 @@ private fun hasParameterHintAtOffset(editor: Editor, file: PsiFile): Boolean {
|
||||
val startOffset = element?.textRange?.startOffset ?: offset
|
||||
val endOffset = element?.textRange?.endOffset ?: offset
|
||||
|
||||
return editor.inlayModel is InlayModelImpl && editor.inlayModel
|
||||
return editor.inlayModel
|
||||
.getInlineElementsInRange(startOffset, endOffset)
|
||||
.find { ParameterHintsPresentationManager.getInstance().isParameterHint(it) } != null
|
||||
}
|
||||
|
||||
@@ -1409,9 +1409,8 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo
|
||||
for (String pane : myFlattenPackages.keySet()) {
|
||||
setPaneOption(myFlattenPackages, flattenPackages, pane, true);
|
||||
}
|
||||
} else {
|
||||
setPaneOption(myFlattenPackages, flattenPackages, paneId, true);
|
||||
}
|
||||
setPaneOption(myFlattenPackages, flattenPackages, paneId, true);
|
||||
}
|
||||
|
||||
public boolean isFoldersAlwaysOnTop() {
|
||||
@@ -1514,9 +1513,8 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo
|
||||
for (String pane : myHideEmptyPackages.keySet()) {
|
||||
setPaneOption(myHideEmptyPackages, hideEmptyPackages, pane, true);
|
||||
}
|
||||
} else {
|
||||
setPaneOption(myHideEmptyPackages, hideEmptyPackages, paneId, true);
|
||||
}
|
||||
setPaneOption(myHideEmptyPackages, hideEmptyPackages, paneId, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-4
@@ -25,8 +25,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class FormatterBasedIndentAdjuster {
|
||||
|
||||
private static final String ADJUST_INDENT_COMMAND_NAME = "Adjust Indent";
|
||||
|
||||
private FormatterBasedIndentAdjuster() {
|
||||
}
|
||||
|
||||
@@ -57,10 +55,10 @@ public class FormatterBasedIndentAdjuster {
|
||||
|
||||
public void run() {
|
||||
int lineStart = myDocument.getLineStartOffset(myLine);
|
||||
CommandProcessor.getInstance().executeCommand(myProject, () ->
|
||||
CommandProcessor.getInstance().runUndoTransparentAction(() ->
|
||||
ApplicationManager.getApplication().runWriteAction(() -> {
|
||||
CodeStyleManager.getInstance(myProject).adjustLineIndent(myDocument, lineStart);
|
||||
}), ADJUST_INDENT_COMMAND_NAME, null);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.vfs.InvalidVirtualFileAccessException;
|
||||
import com.intellij.openapi.vfs.newvfs.FileAttribute;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.FSRecords;
|
||||
import com.intellij.psi.stubs.StubIndexKey;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.intellij.util.containers.ConcurrentIntObjectMap;
|
||||
@@ -198,7 +199,7 @@ public class IndexingStamp {
|
||||
|
||||
while(stream.available() > 0) {
|
||||
ID<?, ?> id = ID.findById(DataInputOutputUtil.readINT(stream));
|
||||
if (id != null) {
|
||||
if (id != null && !(id instanceof StubIndexKey)) {
|
||||
long stamp = getIndexCreationStamp(id);
|
||||
if (stamp == 0) continue; // All (indices) IDs should be valid in this running session (e.g. we can have ID instance existing but index is not registered)
|
||||
if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap<>(5, 0.98f);
|
||||
@@ -209,7 +210,8 @@ public class IndexingStamp {
|
||||
if (outdatedIndices != null) {
|
||||
for(int outdatedIndexId:outdatedIndices) {
|
||||
ID<?, ?> id = ID.findById(outdatedIndexId);
|
||||
if (id != null) {
|
||||
if (id != null && !(id instanceof StubIndexKey)) {
|
||||
if (getIndexCreationStamp(id) == 0) continue; // All (indices) IDs should be valid in this running session (e.g. we can have ID instance existing but index is not registered)
|
||||
long stamp = INDEX_DATA_OUTDATED_STAMP;
|
||||
if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap<>(5, 0.98f);
|
||||
if (stamp <= dominatingIndexStamp) myIndexStamps.put(id, stamp);
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.ide.plugins;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.PluginAware;
|
||||
import com.intellij.openapi.extensions.PluginDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Implement this class in your plugin if there is another plugin which functionality covers functionality provided by this plugin so there
|
||||
* is no sense to have the both plugins installed together. This will instruct the IDE to suggest a user to disable this plugin when he
|
||||
* downloads the new plugin in Settings | Plugins.
|
||||
* <p/>
|
||||
* The implementation must be registered in plugin.xml of the plugin you want to replace:
|
||||
* <pre>
|
||||
* <extensions defaultExtensionNs="com.intellij">
|
||||
* <pluginReplacement implementation="qualified-class-name"/>
|
||||
* </extensions>
|
||||
* </pre>
|
||||
*
|
||||
* @author nik
|
||||
*/
|
||||
public abstract class PluginReplacement implements PluginAware {
|
||||
public static final ExtensionPointName<PluginReplacement> EP_NAME = ExtensionPointName.create("com.intellij.pluginReplacement");
|
||||
private final String myNewPluginId;
|
||||
private PluginDescriptor myPluginDescriptor;
|
||||
|
||||
protected PluginReplacement(String newPluginId) {
|
||||
myNewPluginId = newPluginId;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getReplacementMessage(@NotNull IdeaPluginDescriptor oldPlugin, @NotNull IdeaPluginDescriptor newPlugin) {
|
||||
return "<html>'" + newPlugin.getName() + "' plugin is designed as a replacement for currently installed '" + oldPlugin.getName() + "' plugin.<br> Do you want to " +
|
||||
"disable '" + oldPlugin.getName() + "' to avoid possible conflicts?</html>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPluginDescriptor(PluginDescriptor pluginDescriptor) {
|
||||
myPluginDescriptor = pluginDescriptor;
|
||||
}
|
||||
|
||||
public final PluginDescriptor getOldPluginDescriptor() {
|
||||
return myPluginDescriptor;
|
||||
}
|
||||
|
||||
public final String getNewPluginId() {
|
||||
return myNewPluginId;
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ public class InstallPluginAction extends AnAction implements DumbAware {
|
||||
}
|
||||
};
|
||||
final List<IdeaPluginDescriptor> plugins = myHost.getPluginsModel().getAllPlugins();
|
||||
PluginManagerMain.downloadPlugins(list, PluginManagerMain.mapToPluginIds(plugins), onInstallRunnable, cleanupRunnable);
|
||||
PluginManagerMain.downloadPlugins(list, PluginManagerMain.mapToPluginIds(plugins), onInstallRunnable, pluginEnabler, cleanupRunnable);
|
||||
}
|
||||
catch (final IOException e1) {
|
||||
ourInstallingNodes.removeAll(list);
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.ide.startup.StartupActionScriptManager;
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.notification.Notifications;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.application.ex.ApplicationInfoEx;
|
||||
import com.intellij.openapi.extensions.PluginId;
|
||||
@@ -27,6 +28,7 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.updateSettings.impl.PluginDownloader;
|
||||
import com.intellij.openapi.updateSettings.impl.UpdateSettings;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.GuiUtils;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
@@ -35,14 +37,12 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.ZipUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author stathik
|
||||
@@ -57,10 +57,11 @@ public class PluginInstaller {
|
||||
|
||||
public static boolean prepareToInstall(List<PluginNode> pluginsToInstall,
|
||||
List<PluginId> allPlugins,
|
||||
PluginManagerMain.PluginEnabler pluginEnabler,
|
||||
@NotNull ProgressIndicator indicator) {
|
||||
updateUrls(pluginsToInstall, indicator);
|
||||
Set<PluginNode> dependant = new THashSet<>();
|
||||
boolean install = prepareToInstall(pluginsToInstall, allPlugins, dependant, indicator);
|
||||
boolean install = prepareToInstall(pluginsToInstall, allPlugins, dependant, pluginEnabler, indicator);
|
||||
for (PluginNode node : dependant) {
|
||||
if (!pluginsToInstall.contains(node)) {
|
||||
pluginsToInstall.add(node);
|
||||
@@ -110,6 +111,7 @@ public class PluginInstaller {
|
||||
private static boolean prepareToInstall(List<PluginNode> pluginsToInstall,
|
||||
List<PluginId> allPlugins,
|
||||
Set<PluginNode> installedDependant,
|
||||
PluginManagerMain.PluginEnabler pluginEnabler,
|
||||
@NotNull ProgressIndicator indicator) {
|
||||
List<PluginId> pluginIds = new SmartList<>();
|
||||
for (PluginNode pluginNode : pluginsToInstall) {
|
||||
@@ -120,7 +122,7 @@ public class PluginInstaller {
|
||||
for (PluginNode pluginNode : pluginsToInstall) {
|
||||
indicator.setText(pluginNode.getName());
|
||||
try {
|
||||
result |= prepareToInstall(pluginNode, pluginIds, allPlugins, installedDependant, indicator);
|
||||
result |= prepareToInstall(pluginNode, pluginIds, allPlugins, installedDependant, pluginEnabler, indicator);
|
||||
}
|
||||
catch (IOException e) {
|
||||
String title = IdeBundle.message("title.plugin.error");
|
||||
@@ -136,6 +138,7 @@ public class PluginInstaller {
|
||||
List<PluginId> pluginIds,
|
||||
List<PluginId> allPlugins,
|
||||
Set<PluginNode> installedDependant,
|
||||
PluginManagerMain.PluginEnabler pluginEnabler,
|
||||
@NotNull ProgressIndicator indicator) throws IOException {
|
||||
installedDependant.add(pluginNode);
|
||||
|
||||
@@ -181,7 +184,7 @@ public class PluginInstaller {
|
||||
catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
if (!proceed[0] || !prepareToInstall(depends, allPlugins, installedDependant, indicator)) {
|
||||
if (!proceed[0] || !prepareToInstall(depends, allPlugins, installedDependant, pluginEnabler, indicator)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -199,12 +202,29 @@ public class PluginInstaller {
|
||||
catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
if (proceed[0] && !prepareToInstall(optionalDeps, allPlugins, installedDependant, indicator)) {
|
||||
if (proceed[0] && !prepareToInstall(optionalDeps, allPlugins, installedDependant, pluginEnabler, indicator)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ref<IdeaPluginDescriptor> toDisable = Ref.create(null);
|
||||
Optional<PluginReplacement> replacement = StreamEx.of(PluginReplacement.EP_NAME.getExtensions())
|
||||
.findFirst(r -> r.getNewPluginId().equals(pluginNode.getPluginId().getIdString()));
|
||||
if (replacement.isPresent()) {
|
||||
PluginReplacement pluginReplacement = replacement.get();
|
||||
IdeaPluginDescriptor oldPlugin = PluginManager.getPlugin(pluginReplacement.getOldPluginDescriptor().getPluginId());
|
||||
if (oldPlugin != null && !pluginEnabler.isDisabled(oldPlugin.getPluginId())) {
|
||||
ApplicationManager.getApplication().invokeAndWait(() -> {
|
||||
String title = IdeBundle.message("plugin.manager.obsolete.plugins.detected.title");
|
||||
String message = pluginReplacement.getReplacementMessage(oldPlugin, pluginNode);
|
||||
if (Messages.showYesNoDialog(message, title, Messages.getWarningIcon()) == Messages.YES) {
|
||||
toDisable.set(oldPlugin);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
PluginDownloader downloader = PluginDownloader.createDownloader(pluginNode, pluginNode.getRepositoryName(), null);
|
||||
|
||||
if (downloader.prepareToInstall(indicator)) {
|
||||
@@ -212,6 +232,9 @@ public class PluginInstaller {
|
||||
downloader.install();
|
||||
}
|
||||
pluginNode.setStatus(PluginNode.STATUS_DOWNLOADED);
|
||||
if (!toDisable.isNull()) {
|
||||
pluginEnabler.disablePlugins(Collections.singleton(toDisable.get()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
||||
@@ -50,7 +50,6 @@ import com.intellij.ui.border.CustomLineBorder;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.ui.speedSearch.SpeedSearchSupply;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
@@ -408,17 +407,28 @@ public abstract class PluginManagerMain implements Disposable {
|
||||
loadPluginsFromHostInBackground();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #downloadPlugins(List, List, Runnable, PluginEnabler, Runnable)} instead
|
||||
*/
|
||||
public static boolean downloadPlugins(final List<PluginNode> plugins,
|
||||
final List<PluginId> allPlugins,
|
||||
final Runnable onSuccess,
|
||||
@Nullable final Runnable cleanup) throws IOException {
|
||||
return downloadPlugins(plugins, allPlugins, onSuccess, new PluginEnabler.HEADLESS(), cleanup);
|
||||
}
|
||||
|
||||
public static boolean downloadPlugins(final List<PluginNode> plugins,
|
||||
final List<PluginId> allPlugins,
|
||||
final Runnable onSuccess,
|
||||
PluginEnabler pluginEnabler,
|
||||
@Nullable final Runnable cleanup) throws IOException {
|
||||
final boolean[] result = new boolean[1];
|
||||
try {
|
||||
ProgressManager.getInstance().run(new Task.Backgroundable(null, IdeBundle.message("progress.download.plugins"), true, PluginManagerUISettings.getInstance()) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
try {
|
||||
if (PluginInstaller.prepareToInstall(plugins, allPlugins, indicator)) {
|
||||
if (PluginInstaller.prepareToInstall(plugins, allPlugins, pluginEnabler, indicator)) {
|
||||
ApplicationManager.getApplication().invokeLater(onSuccess);
|
||||
result[0] = true;
|
||||
}
|
||||
@@ -708,6 +718,7 @@ public abstract class PluginManagerMain implements Disposable {
|
||||
|
||||
public interface PluginEnabler {
|
||||
void enablePlugins(Set<IdeaPluginDescriptor> disabled);
|
||||
void disablePlugins(Set<IdeaPluginDescriptor> disabled);
|
||||
|
||||
boolean isDisabled(PluginId pluginId);
|
||||
|
||||
@@ -719,6 +730,13 @@ public abstract class PluginManagerMain implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disablePlugins(Set<IdeaPluginDescriptor> disabled) {
|
||||
for (IdeaPluginDescriptor descriptor : disabled) {
|
||||
PluginManagerCore.disablePlugin(descriptor.getPluginId().getIdString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisabled(PluginId pluginId) {
|
||||
return isDisabled(pluginId.getIdString());
|
||||
@@ -739,7 +757,12 @@ public abstract class PluginManagerMain implements Disposable {
|
||||
|
||||
@Override
|
||||
public void enablePlugins(Set<IdeaPluginDescriptor> disabled) {
|
||||
pluginsModel.enableRows(disabled.toArray(new IdeaPluginDescriptor[disabled.size()]), true);
|
||||
pluginsModel.enableRows(disabled.toArray(new IdeaPluginDescriptor[0]), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disablePlugins(Set<IdeaPluginDescriptor> disabled) {
|
||||
pluginsModel.enableRows(disabled.toArray(new IdeaPluginDescriptor[0]), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+11
-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.
|
||||
@@ -168,6 +168,16 @@ public class DarculaRadioButtonUI extends MetalRadioButtonUI {
|
||||
mnemIndex, textRect.x, textRect.y + fm.getAscent());
|
||||
}
|
||||
}
|
||||
|
||||
if(b.hasFocus() && b.isFocusPainted() &&
|
||||
textRect.width > 0 && textRect.height > 0 ) {
|
||||
paintFocus(g, textRect, b.getSize());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintFocus(Graphics g, Rectangle t, Dimension d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
@@ -16,6 +16,7 @@
|
||||
package com.intellij.ide.ui.laf.intellij;
|
||||
|
||||
import com.intellij.ide.ui.laf.darcula.ui.DarculaRadioButtonUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
@@ -40,4 +41,12 @@ public class WinIntelliJRadioButtonUI extends DarculaRadioButtonUI {
|
||||
final int y = (viewRect.height - icon.getIconHeight()) / 2;
|
||||
icon.paintIcon(c, g, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintFocus(Graphics g, Rectangle t, Dimension d) {
|
||||
g.setColor(getFocusColor());
|
||||
t.x -= 2; t.y -=1;
|
||||
t.width += 3; t.height +=2;
|
||||
UIUtil.drawDottedRectangle(g, t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.intellij.openapi.editor.colors.impl.DelegateColorScheme;
|
||||
import com.intellij.openapi.editor.event.EditorMouseEvent;
|
||||
import com.intellij.openapi.editor.ex.*;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.editor.markup.*;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -171,6 +172,9 @@ class EventLogConsole {
|
||||
}
|
||||
});
|
||||
editor.setColorsScheme(ConsoleViewUtil.updateConsoleColorScheme(editor.createBoundColorSchemeDelegate(globalScheme)));
|
||||
if (editor instanceof EditorImpl) {
|
||||
((EditorImpl)editor).setUseEditorAntialiasing(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static DefaultActionGroup createPopupActions(ActionManager actionManager,
|
||||
|
||||
+10
-27
@@ -19,7 +19,6 @@ import com.intellij.ide.IdeEventQueue;
|
||||
import com.intellij.idea.IdeaApplication;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.*;
|
||||
import com.intellij.openapi.diagnostic.FrequentEventDetector;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
@@ -54,8 +53,6 @@ public class LaterInvocator {
|
||||
private static final boolean DEBUG = LOG.isDebugEnabled();
|
||||
|
||||
private static final Object LOCK = new Object();
|
||||
private static final IdeEventQueue ourEventQueue = IdeEventQueue.getInstance();
|
||||
private static final FrequentEventDetector ourFrequentEventDetector = new FrequentEventDetector(1009, 100);
|
||||
|
||||
private LaterInvocator() { }
|
||||
|
||||
@@ -94,8 +91,6 @@ public class LaterInvocator {
|
||||
private static volatile int ourQueueSkipCount; // optimization
|
||||
private static final FlushQueue ourFlushQueueRunnable = new FlushQueue();
|
||||
|
||||
private static final Stack<AWTEvent> ourEventStack = new Stack<>(); // guarded by RUN_LOCK
|
||||
|
||||
private static final EventDispatcher<ModalityStateListener> ourModalityStateMulticaster = EventDispatcher.create(ModalityStateListener.class);
|
||||
|
||||
public static void addModalityStateListener(@NotNull ModalityStateListener listener, @NotNull Disposable parentDisposable) {
|
||||
@@ -146,8 +141,6 @@ public class LaterInvocator {
|
||||
|
||||
@NotNull
|
||||
static ActionCallback invokeLater(@NotNull Runnable runnable, @NotNull ModalityState modalityState, @NotNull Condition<?> expired) {
|
||||
ourFrequentEventDetector.eventHappened(runnable);
|
||||
|
||||
final ActionCallback callback = new ActionCallback();
|
||||
RunnableInfo runnableInfo = new RunnableInfo(runnable, modalityState, expired, callback);
|
||||
synchronized (LOCK) {
|
||||
@@ -394,7 +387,6 @@ public class LaterInvocator {
|
||||
}
|
||||
|
||||
private static final AtomicBoolean FLUSHER_SCHEDULED = new AtomicBoolean(false);
|
||||
private static final Object RUN_LOCK = new Object();
|
||||
|
||||
private static class FlushQueue implements Runnable {
|
||||
@SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized") private RunnableInfo myLastInfo;
|
||||
@@ -412,25 +404,16 @@ public class LaterInvocator {
|
||||
myLastInfo = lastInfo;
|
||||
|
||||
if (lastInfo != null) {
|
||||
synchronized (RUN_LOCK) { // necessary only because of switching to our own event queue
|
||||
AWTEvent event = ourEventQueue.getTrueCurrentEvent();
|
||||
ourEventStack.push(event);
|
||||
int stackSize = ourEventStack.size();
|
||||
|
||||
try {
|
||||
lastInfo.runnable.run();
|
||||
lastInfo.callback.setDone();
|
||||
}
|
||||
catch (ProcessCanceledException ignored) { }
|
||||
catch (Throwable t) {
|
||||
LOG.error(t);
|
||||
}
|
||||
finally {
|
||||
LOG.assertTrue(ourEventStack.size() == stackSize);
|
||||
ourEventStack.pop();
|
||||
|
||||
if (!DEBUG) myLastInfo = null;
|
||||
}
|
||||
try {
|
||||
lastInfo.runnable.run();
|
||||
lastInfo.callback.setDone();
|
||||
}
|
||||
catch (ProcessCanceledException ignored) { }
|
||||
catch (Throwable t) {
|
||||
LOG.error(t);
|
||||
}
|
||||
finally {
|
||||
if (!DEBUG) myLastInfo = null;
|
||||
}
|
||||
}
|
||||
return lastInfo != null;
|
||||
|
||||
+80
-88
@@ -20,12 +20,10 @@ import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditorStateLevel;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
|
||||
import com.intellij.openapi.progress.util.ReadTask;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.EmptyRunnable;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
@@ -36,20 +34,18 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class AsyncEditorLoader {
|
||||
private static final ExecutorService ourExecutor = AppExecutorUtil.createBoundedApplicationPoolExecutor("AsyncEditorLoader pool",2);
|
||||
private static final ExecutorService ourExecutor = AppExecutorUtil.createBoundedApplicationPoolExecutor("AsyncEditorLoader pool", 2);
|
||||
private static final Key<AsyncEditorLoader> ASYNC_LOADER = Key.create("ASYNC_LOADER");
|
||||
private static final int SYNCHRONOUS_LOADING_WAITING_TIME_MS = 200;
|
||||
private static final int RETRY_TIME_MS = 10;
|
||||
@NotNull private final Editor myEditor;
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final TextEditorImpl myTextEditor;
|
||||
@NotNull private final TextEditorComponent myEditorComponent;
|
||||
@NotNull private final TextEditorProvider myProvider;
|
||||
private boolean myLoaded;
|
||||
private final List<Runnable> myDelayedActions = new ArrayList<>();
|
||||
private TextEditorState myDelayedState;
|
||||
private final CompletableFuture<?> myLoadingFinished = new CompletableFuture<>();
|
||||
@@ -67,94 +63,90 @@ public class AsyncEditorLoader {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Future<?> scheduleBackgroundLoading(boolean firstTime) {
|
||||
ReadTask task = new ReadTask() {
|
||||
PsiDocumentManager pdm = PsiDocumentManager.getInstance(myProject);
|
||||
long startStamp = myEditor.getDocument().getModificationStamp();
|
||||
|
||||
@Override
|
||||
public Continuation runBackgroundProcess(@NotNull ProgressIndicator indicator) throws ProcessCanceledException {
|
||||
return pdm.commitAndRunReadAction(() -> {
|
||||
if (myEditorComponent.isDisposed()) {
|
||||
loadingFinished();
|
||||
return null;
|
||||
}
|
||||
|
||||
Runnable applyResults = myTextEditor.loadEditorInBackground();
|
||||
return new Continuation(() -> {
|
||||
if (startStamp != myEditor.getDocument().getModificationStamp()) {
|
||||
onCanceled(indicator);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
applyResults.run();
|
||||
}
|
||||
finally {
|
||||
loadingFinished();
|
||||
}
|
||||
}, ModalityState.any());
|
||||
});
|
||||
Future<?> start() {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
Future<Runnable> continuationFuture = scheduleLoading();
|
||||
boolean showProgress = true;
|
||||
if (worthWaiting()) {
|
||||
/*
|
||||
* Possible alternatives:
|
||||
* 1. show "Loading" from the beginning, then it'll be always noticeable at least in fade-out phase
|
||||
* 2. show a gray screen for some time and then "Loading" if it's still loading; it'll produce quick background blinking for all editors
|
||||
* 3. show non-highlighted and unfolded editor as "Loading" background and allow it to relayout at the end of loading phase
|
||||
* 4. freeze EDT a bit and hope that for small editors it'll suffice and for big ones show "Loading" after that.
|
||||
* This strategy seems to produce minimal blinking annoyance.
|
||||
*/
|
||||
Runnable continuation = resultInTimeOrNull(continuationFuture, SYNCHRONOUS_LOADING_WAITING_TIME_MS);
|
||||
if (continuation != null) {
|
||||
showProgress = false;
|
||||
loadingFinished(continuation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled(@NotNull ProgressIndicator indicator) {
|
||||
if (!myEditorComponent.isDisposed() && !myProject.isDisposed()) {
|
||||
scheduleBackgroundLoading(false);
|
||||
}
|
||||
else {
|
||||
loadingFinished();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!firstTime || !loadImmediately(task)) {
|
||||
myEditorComponent.startLoading();
|
||||
ProgressIndicatorUtils.scheduleWithWriteActionPriority(new ProgressIndicatorBase(), ourExecutor, task);
|
||||
}
|
||||
if (showProgress) myEditorComponent.startLoading();
|
||||
return myLoadingFinished;
|
||||
}
|
||||
|
||||
/**
|
||||
* Possible alternatives:
|
||||
* 1. show "Loading" from the beginning, then it'll be always noticeable at least in fade-out phase
|
||||
* 2. show a gray screen for some time and then "Loading" if it's still loading; it'll produce quick background blinking for all editors
|
||||
* 3. show non-highlighted and unfolded editor as "Loading" background and allow it to relayout at the end of loading phase
|
||||
* 4. freeze EDT a bit and hope that for small editors it'll suffice and for big ones show "Loading" after that.
|
||||
* This strategy seems to produce minimal blinking annoyance.
|
||||
*/
|
||||
private boolean loadImmediately(@NotNull ReadTask task) {
|
||||
if (PsiDocumentManager.getInstance(myProject).hasUncommitedDocuments() ||
|
||||
ApplicationManager.getApplication().isWriteAccessAllowed()) {
|
||||
return false; // cannot perform commitAndRunReadAction in parallel to EDT waiting
|
||||
}
|
||||
|
||||
ProgressIndicatorBase indicator = new ProgressIndicatorBase();
|
||||
Future<ReadTask.Continuation> future = ourExecutor.submit(() -> {
|
||||
Ref<ReadTask.Continuation> continuationRef = Ref.create();
|
||||
ProgressIndicatorUtils.runWithWriteActionPriority(() -> continuationRef.set(task.runBackgroundProcess(indicator)), indicator);
|
||||
return continuationRef.get();
|
||||
});
|
||||
try {
|
||||
ReadTask.Continuation applyImmediately = future.get(200, TimeUnit.MILLISECONDS);
|
||||
if (applyImmediately != null) {
|
||||
applyImmediately.getAction().run();
|
||||
return true;
|
||||
private Future<Runnable> scheduleLoading() {
|
||||
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(myProject);
|
||||
long startStamp = myEditor.getDocument().getModificationStamp();
|
||||
return ourExecutor.submit(() -> {
|
||||
Ref<Runnable> ref = new Ref<>();
|
||||
while (!myEditorComponent.isDisposed()) {
|
||||
ProgressIndicatorUtils.runWithWriteActionPriority(
|
||||
() -> ref.set(psiDocumentManager.commitAndRunReadAction(() -> myProject.isDisposed() ? EmptyRunnable.INSTANCE
|
||||
: myTextEditor.loadEditorInBackground())),
|
||||
new ProgressIndicatorBase()
|
||||
);
|
||||
Runnable continuation = ref.get();
|
||||
if (continuation != null) {
|
||||
invokeLater(() -> {
|
||||
if (startStamp == myEditor.getDocument().getModificationStamp()) loadingFinished(continuation);
|
||||
else if (!myProject.isDisposed() && !myEditorComponent.isDisposed()) scheduleLoading();
|
||||
});
|
||||
return continuation;
|
||||
}
|
||||
TimeUnit.MILLISECONDS.sleep(RETRY_TIME_MS);
|
||||
}
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
}
|
||||
|
||||
indicator.cancel();
|
||||
return false;
|
||||
invokeLater(() -> loadingFinished(null));
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void loadingFinished() {
|
||||
private static void invokeLater(Runnable runnable) {
|
||||
ApplicationManager.getApplication().invokeLater(runnable, ModalityState.any());
|
||||
}
|
||||
|
||||
private boolean worthWaiting() {
|
||||
// cannot perform commitAndRunReadAction in parallel to EDT waiting
|
||||
return !PsiDocumentManager.getInstance(myProject).hasUncommitedDocuments() &&
|
||||
!ApplicationManager.getApplication().isWriteAccessAllowed();
|
||||
}
|
||||
|
||||
private static <T> T resultInTimeOrNull(Future<T> future, long timeMs) {
|
||||
try {
|
||||
return future.get(timeMs, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (InterruptedException | TimeoutException ignored) {}
|
||||
catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void loadingFinished(Runnable continuation) {
|
||||
if (myLoadingFinished.isDone()) return;
|
||||
myLoadingFinished.complete(null);
|
||||
myEditor.putUserData(ASYNC_LOADER, null);
|
||||
myLoaded = true;
|
||||
|
||||
if (myEditorComponent.isDisposed()) return;
|
||||
myEditorComponent.stopLoading();
|
||||
|
||||
if (continuation != null) {
|
||||
continuation.run();
|
||||
}
|
||||
|
||||
if (myEditorComponent.isLoading()) {
|
||||
myEditorComponent.stopLoading();
|
||||
}
|
||||
myEditorComponent.getContentPanel().setVisible(true);
|
||||
|
||||
if (myDelayedState != null) {
|
||||
@@ -193,7 +185,7 @@ public class AsyncEditorLoader {
|
||||
|
||||
|
||||
TextEditorState state = myProvider.getStateImpl(myProject, myEditor, level);
|
||||
if (!myLoaded && myDelayedState != null) {
|
||||
if (!myLoadingFinished.isDone() && myDelayedState != null) {
|
||||
state.setDelayedFoldState(myDelayedState::getFoldingState);
|
||||
}
|
||||
return state;
|
||||
@@ -202,7 +194,7 @@ public class AsyncEditorLoader {
|
||||
void setEditorState(@NotNull final TextEditorState state) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
|
||||
if (!myLoaded) {
|
||||
if (!myLoadingFinished.isDone()) {
|
||||
myDelayedState = state;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ class TextEditorComponent extends JBLoadingPanel implements DataProvider {
|
||||
});
|
||||
}
|
||||
|
||||
private boolean myDisposed;
|
||||
private volatile boolean myDisposed;
|
||||
/**
|
||||
* Disposes all resources allocated be the TextEditorComponent. It disposes all created
|
||||
* editors, unregisters listeners. The behaviour of the splitter after disposing is
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ public class TextEditorImpl extends UserDataHolderBase implements TextEditor {
|
||||
myChangeSupport = new PropertyChangeSupport(this);
|
||||
myComponent = createEditorComponent(project, file);
|
||||
myAsyncLoader = new AsyncEditorLoader(this, myComponent, provider);
|
||||
myLoadingFinished = myAsyncLoader.scheduleBackgroundLoading(true);
|
||||
myLoadingFinished = myAsyncLoader.start();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -22,10 +22,13 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import static com.intellij.openapi.options.ex.ConfigurableCardPanel.createConfigurableComponent;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public abstract class TabbedConfigurable extends CompositeConfigurable<Configurable> {
|
||||
public abstract class TabbedConfigurable extends CompositeConfigurable<Configurable> implements Configurable.NoScroll,
|
||||
Configurable.NoMargin {
|
||||
protected TabbedPaneWrapper myTabbedPane;
|
||||
private final Disposable myParentDisposable;
|
||||
|
||||
@@ -38,13 +41,14 @@ public abstract class TabbedConfigurable extends CompositeConfigurable<Configura
|
||||
myTabbedPane = new TabbedPaneWrapper(myParentDisposable);
|
||||
createConfigurableTabs();
|
||||
final JComponent component = myTabbedPane.getComponent();
|
||||
component.setBorder(JBUI.Borders.emptyTop(5));
|
||||
component.setPreferredSize(JBUI.size(500, 400));
|
||||
return component;
|
||||
}
|
||||
|
||||
protected void createConfigurableTabs() {
|
||||
for (Configurable configurable : getConfigurables()) {
|
||||
myTabbedPane.addTab(configurable.getDisplayName(), configurable.createComponent());
|
||||
myTabbedPane.addTab(configurable.getDisplayName(), createConfigurableComponent(configurable));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user