diff --git a/build/groovy/org/jetbrains/intellij/build/IdeaCommunityProperties.groovy b/build/groovy/org/jetbrains/intellij/build/IdeaCommunityProperties.groovy index 11a1fe8b19d9..1ee9b0fcd343 100644 --- a/build/groovy/org/jetbrains/intellij/build/IdeaCommunityProperties.groovy +++ b/build/groovy/org/jetbrains/intellij/build/IdeaCommunityProperties.groovy @@ -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" + } } } diff --git a/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy b/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy index 497ac852fc28..63641a9aa701 100644 --- a/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy +++ b/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy @@ -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 + } } diff --git a/build/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy b/build/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy index b65bcf5638b5..0d6319b9b30a 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy @@ -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 diff --git a/build/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy index 9e14043862f7..bdd63baaaaeb 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy @@ -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 diff --git a/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy index efc5f29bd160..19d92d0b9752 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy @@ -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 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 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) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java index 40764bf435ff..d09979acea69 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java @@ -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 l.lineNumber() == myLastLine) .findFirst().ifPresent(location -> createLocationBreakpointRequest(location, debugProcess)); diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java index 4a5bd3143b97..49f6ede26e1e 100644 --- a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java @@ -267,8 +267,7 @@ public class JavaBreakpointFiltersPanel s, String concator, int N, String NthConcator) { diff --git a/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java b/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java index 32519472d723..61d0172f3384 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java +++ b/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java @@ -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)() -> 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; diff --git a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java index d63f2bc7bd4f..7ed83d254664 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java +++ b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java @@ -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) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 9fc11002ed18..c7d1b15bd4cf 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -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); diff --git a/java/java-impl/src/com/intellij/codeInspection/streamMigration/MigrateToStreamFix.java b/java/java-impl/src/com/intellij/codeInspection/streamMigration/MigrateToStreamFix.java index 2bdbe16a8973..2a34ec766033 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/MigrateToStreamFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/MigrateToStreamFix.java @@ -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); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java b/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java index 13281bd34db4..a837bc5ccb91 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java @@ -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 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 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 = ;...;...) @@ -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 operations() { + StreamEx operations() { return StreamEx.iterate(myPreviousOp, Objects::nonNull, Operation::getPreviousOp); } diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java index e00821d3f98a..52f193742000 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java @@ -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)) { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index fa92d548a366..3b67150d9a5e 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -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 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; diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/MigrateGetterNameSetting.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/MigrateGetterNameSetting.java index a8a76800dc90..36dd706410cc 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/MigrateGetterNameSetting.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/MigrateGetterNameSetting.java @@ -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 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); } }); } diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptorBase.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptorBase.java index 5213fadd83ee..a3c68a6abcc7 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptorBase.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptorBase.java @@ -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; } diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeEvaluator.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeEvaluator.java index aef757746501..7bbea4a2bca3 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeEvaluator.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeEvaluator.java @@ -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 types = myTypeMap.get(info); - final StringBuffer b = new StringBuffer(); + final StringBuilder b = new StringBuilder(); if (types != null) { b.append(info.getElement()).append(" : "); diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java index cdba34131b75..0ea58844270f 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java @@ -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 myProcessedRoots = new HashSet<>(); public TypeMigrationLabeler(final TypeMigrationRules rules, PsiType rootType) { - this(rules, Functions.constant(rootType)); + this(rules, Functions.constant(rootType)); } public TypeMigrationLabeler(final TypeMigrationRules rules, Function 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> roots = - (LinkedList>)myMigrationRoots.clone(); + final List> roots = new ArrayList<>(myMigrationRoots); myMigrationRoots = new LinkedList<>(); diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationProcessor.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationProcessor.java index d8d2fbefc036..9ddcf9b03aa8 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationProcessor.java @@ -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 myRootTypes; + private final Function 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.constant(migrationType), optimizeImports); + runHighlightingTypeMigration(project, editor, rules, new PsiElement[] {root}, Functions.constant(migrationType), optimizeImports); } diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java index f58f2eb585d4..80ab5601ed58 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java @@ -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.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() { diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/actions/ChangeTypeSignatureAction.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/actions/ChangeTypeSignatureAction.java index 943acea256d9..98fe842aeb75 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/actions/ChangeTypeSignatureAction.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/actions/ChangeTypeSignatureAction.java @@ -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) { diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/rules/RootTypeConversionRule.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/rules/RootTypeConversionRule.java index a4895d63f747..7c4551fe8466 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/rules/RootTypeConversionRule.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/rules/RootTypeConversionRule.java @@ -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()); diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/FailedConversionsDialog.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/FailedConversionsDialog.java index 103375899e33..2a845ac7254a 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/FailedConversionsDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/FailedConversionsDialog.java @@ -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("

"); diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationNode.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationNode.java index d8e6ea77a044..53252e161482 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationNode.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationNode.java @@ -121,8 +121,4 @@ public class MigrationNode extends AbstractTreeNode impl public MigrationNode getDuplicate() { return myDuplicatedNode; } - - public boolean hasDuplicate() { - return myDuplicatedNode != null; - } } diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationPanel.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationPanel.java index bc42a40658db..3173cc671b4e 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationPanel.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationPanel.java @@ -187,15 +187,14 @@ public class MigrationPanel extends JPanel implements Disposable { if (userObject instanceof MigrationRootNode) { ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> { final HashSet files = new HashSet<>(); - final TypeMigrationUsageInfo[] usages = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public TypeMigrationUsageInfo[] compute() { + final TypeMigrationUsageInfo[] usages = ApplicationManager.getApplication().runReadAction( + (Computable)() -> { final Collection 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; diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationRootNode.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationRootNode.java index 8c210503e0b2..06cc4b736259 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationRootNode.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationRootNode.java @@ -37,7 +37,7 @@ import java.util.*; public class MigrationRootNode extends AbstractTreeNode implements DuplicateNodeRenderer.DuplicatableNode { private final TypeMigrationLabeler myLabeler; private List myCachedChildren; - private final PsiElement myRoots[]; + private final PsiElement[] myRoots; private final boolean myPreviewUsages; protected MigrationRootNode(Project project, diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/OverridenUsageInfo.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/OverriddenUsageInfo.java similarity index 89% rename from java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/OverridenUsageInfo.java rename to java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/OverriddenUsageInfo.java index 3d72c7dad553..cd2ee0a635c3 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/OverridenUsageInfo.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/OverriddenUsageInfo.java @@ -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); } diff --git a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java index 3779effed5fe..13e3894493bb 100644 --- a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java +++ b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java @@ -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) { diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java index ddab945cff0f..4e66505942e4 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java @@ -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 getEdges(ControlFlow flow, int start) { + final List list = new ArrayList(); depthFirstSearch(flow, new InstructionClientVisitor() { @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 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; } /** diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java index f46eeff51d99..3e96911dec34 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java @@ -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 errorMessages = parentSession.getIncompatibleErrorMessages(); if (errorMessages != null) { + properties.getInfo().setInferenceError(StringUtil.join(errorMessages, "\n")); return childSession.prepareSubstitution(); } return childSession.collectAdditionalAndInfer(parameters, arguments, properties, compoundInitialState.getInitialSubstitutor()); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/EraseTypeForNewExpressionWithDiamondsIfUncheckedConversionWasPerformedDuringApplicabilityCheck.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/EraseTypeForNewExpressionWithDiamondsIfUncheckedConversionWasPerformedDuringApplicabilityCheck.java index be8587fc9bc6..169b53cdf0f3 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/EraseTypeForNewExpressionWithDiamondsIfUncheckedConversionWasPerformedDuringApplicabilityCheck.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/EraseTypeForNewExpressionWithDiamondsIfUncheckedConversionWasPerformedDuringApplicabilityCheck.java @@ -6,10 +6,10 @@ class Test { Holder dataHolder = null; Result r3 = new Result<>(new Holder<>(dataHolder)); - Result r4 = Result.create(new Holder<>(dataHolder)); + Result r4 = Result.create(new Holder<>(dataHolder)); Result r5 = new Result<>(Holder.create(dataHolder)); - Result r6 = Result.create(Holder.create(dataHolder)); + Result r6 = Result.create(Holder.create(dataHolder)); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/HighlightArgumentWithProblem.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/HighlightArgumentWithProblem.java index 487a1abb7d0b..f50c9b15107a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/HighlightArgumentWithProblem.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/HighlightArgumentWithProblem.java @@ -7,6 +7,6 @@ class Test2 { } { - foo (bar(String.class), ""); + foo (bar(String.class), ""); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128101.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128101.java index 2d4ff1af0738..f8fd21e75cce 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128101.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128101.java @@ -20,10 +20,10 @@ class TestIDEA128101 { public static void test() { construct(String.class, createPath(integerAttribute), createPath(stringAttribute)); - construct1(String.class, createPath(integerAttribute), createPath(stringAttribute)); + construct1(String.class, createPath(integerAttribute), createPath(stringAttribute)); construct2(String.class, createPath(integerAttribute), createPath(stringAttribute)); - construct3(String.class, createPath(integerAttribute), createPath(stringAttribute)); - construct4(String.class, createPath(integerAttribute), createPath(stringAttribute)); + construct3(String.class, createPath(integerAttribute), createPath(stringAttribute)); + construct4(String.class, createPath(integerAttribute), createPath(stringAttribute)); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/OuterCallOverloads.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/OuterCallOverloads.java index 0b5b2b6f2812..6506a7a48464 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/OuterCallOverloads.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/OuterCallOverloads.java @@ -11,6 +11,6 @@ abstract class Overloadsss { { List l = foo(bar (null)); - List l1 = foo(bar1(null)); + List l1 = foo(bar1(null)); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution3.java index 5f57240f5f0b..407d62494a00 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution3.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution3.java @@ -8,8 +8,8 @@ class Test { IntStream mi = sp.map(Inner::foo); Stream mI = sp.map(Inner::fooBoxed); - IntStream li = sp.map(inner->inner.foo()); - Stream lI = sp.map(inner -> inner.fooBoxed()); + IntStream li = sp.map(inner->inner.foo()); + Stream lI = sp.map(inner -> inner.fooBoxed()); } interface Stream { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguitySpecificReturn.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguitySpecificReturn.java index 291f7e2b0c91..3609928401e6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguitySpecificReturn.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguitySpecificReturn.java @@ -1,8 +1,8 @@ class IntStream { private void foo(IntStream s) { - s.map(i -> 1 << i); - s.map(i -> 1); - s.map(i -> i); + s.map(i -> 1 << i); + s.map(i -> 1); + s.map(i -> i); } public static void main(String[] args) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility.java index 6ee3add7c1fe..6526c304cdde 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility.java @@ -25,7 +25,7 @@ class ReturnTypeIncompatibility { } public static void main(String[] args) { - call(i-> {return i;}); + call(i-> {return i;}); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/TargetTypeParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/TargetTypeParameter.java index 5b246569c17f..ee65e9cf26f3 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/TargetTypeParameter.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/TargetTypeParameter.java @@ -3,7 +3,7 @@ import java.util.function.Supplier; class Test { public static void main(String... args) { - c(() -> 3, () -> 10); + c(() -> 3, () -> 10); } public static void c(Supplier s1, Supplier s2) {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CheckedExceptionsConstraintsSubstitutions1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CheckedExceptionsConstraintsSubstitutions1.java index aff5ea6c4265..b905596c6c72 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CheckedExceptionsConstraintsSubstitutions1.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CheckedExceptionsConstraintsSubstitutions1.java @@ -32,7 +32,7 @@ class Test1 { } { - bar(l -> baz(l)); + bar(l -> baz(l)); bar(this::baz); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA127215.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA127215.java index 226bdb51f9bf..b453df3c9264 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA127215.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA127215.java @@ -26,6 +26,6 @@ class Test { .map(object -> Arrays.stream(functions) .map(fn -> fn.apply(object)) .collect(toList())) - .collect(toList()); + .collect(toList()); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IncludeConstraintsWhenParentMethodIsDuringCalculation.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IncludeConstraintsWhenParentMethodIsDuringCalculation.java index 7d5c0557acf7..98d7319d5ccf 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IncludeConstraintsWhenParentMethodIsDuringCalculation.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IncludeConstraintsWhenParentMethodIsDuringCalculation.java @@ -9,10 +9,7 @@ class Test { SuperFoo foo(I ax) { return null; } - SuperFoo ls = foo(() -> new Foo<>()); + SuperFoo ls = foo(() -> new Foo<>()); SuperFoo li = foo(() -> new Foo<>()); SuperFoo lw = foo(() -> new Foo<>()); } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialApplicability.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialApplicability.java index 18f5026255c6..bda9f7270b74 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialApplicability.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialApplicability.java @@ -31,8 +31,8 @@ class Test { String i1 = instanceCall(this::m0); String i2 = instanceCall(this::m1); String i3 = instanceCall(this::m2); - String i4 = instanceCall(this::m01); - String i5 = instanceCall(this::m012); + String i4 = instanceCall(this::m01); + String i5 = instanceCall(this::m012); } void n0() { } @@ -53,7 +53,7 @@ class Test { Test s1 = staticCall(Test::n0); Test s2 = staticCall(Test::n1); Test s3 = staticCall(Test::n2); - Test s4 = staticCall(Test::n01); - Test s5 = staticCall(Test::n012); + Test s4 = staticCall(Test::n01); + Test s5 = staticCall(Test::n012); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialCompatibilityWithInvalidShape.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialCompatibilityWithInvalidShape.java index 3cfa72c6ee2e..8b2cd92ac7a7 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialCompatibilityWithInvalidShape.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialCompatibilityWithInvalidShape.java @@ -34,7 +34,7 @@ class Test { { Set m = replyWith(this::query); System.out.println(m); - Set m1 = replyWith(this::query1); + Set m1 = replyWith(this::query1); System.out.println(m1); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/UnresolvedMethodReference.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/UnresolvedMethodReference.java index 95219089de50..51d852826aff 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/UnresolvedMethodReference.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/UnresolvedMethodReference.java @@ -4,6 +4,6 @@ import java.util.Comparator; class Main { public void test() { - Collections.sort(new ArrayList<>(), Comparator::reversed); + Collections.sort(new ArrayList<>(), Comparator::reversed); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/SpecificFunctionalInterfaces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/SpecificFunctionalInterfaces.java index 19ddda398cbf..b9db292d5346 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/SpecificFunctionalInterfaces.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/SpecificFunctionalInterfaces.java @@ -14,6 +14,6 @@ class Main { } { - perform(() -> {}); + perform(() -> {}); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollect.java new file mode 100644 index 000000000000..25f7274c3172 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollect.java @@ -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 test(BufferedReader br) throws IOException { + List result; + result = br.lines().map(String::trim).collect(Collectors.toList()); + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollectNestedOk.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollectNestedOk.java new file mode 100644 index 000000000000..53c710fd73a3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollectNestedOk.java @@ -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 test(List readers) throws IOException { + for(BufferedReader br : readers) { + List result; + result = br.lines().map(String::trim).collect(Collectors.toList()); + if(result.size() > 10) { + return result; + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderModifiedLine.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderModifiedLine.java new file mode 100644 index 000000000000..93c99a83b3e0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderModifiedLine.java @@ -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); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderSum.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderSum.java new file mode 100644 index 000000000000..93c99a83b3e0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderSum.java @@ -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); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFilterMapFlatMapArrayMapCollect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFilterMapFlatMapArrayMapCollect.java new file mode 100644 index 000000000000..81e1b7dbcc44 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFilterMapFlatMapArrayMapCollect.java @@ -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 map) { + List result = map.entrySet().stream().filter(entry -> entry.getKey().startsWith("x")).map(Map.Entry::getValue).flatMap(Arrays::stream).map(String::trim).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollect.java new file mode 100644 index 000000000000..23d877d08403 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollect.java @@ -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 test(BufferedReader br) throws IOException { + List result = new ArrayList<>(); + String line = ""; + while(null != (line = br.readLine())) { + result.add(line.trim()); + } + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNested.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNested.java new file mode 100644 index 000000000000..6d050b10678d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNested.java @@ -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 test(List readers) throws IOException { + List result = new ArrayList<>(); + for(BufferedReader br : readers) { + String line = ""; + while (null != (line = br.readLine())) { + result.add(line.trim()); + } + } + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNestedOk.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNestedOk.java new file mode 100644 index 000000000000..46d62990f876 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNestedOk.java @@ -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 test(List readers) throws IOException { + for(BufferedReader br : readers) { + List result = new ArrayList<>(); + String line = ""; + while (null != (line = br.readLine())) { + result.add(line.trim()); + } + if(result.size() > 10) { + return result; + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderComplexModifiedLine.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderComplexModifiedLine.java new file mode 100644 index 000000000000..187dc491ef1b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderComplexModifiedLine.java @@ -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; + while((line = br.readLine()) != null) { + count+=(line = line.trim()).length(); + } + System.out.println(count); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderModifiedLine.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderModifiedLine.java new file mode 100644 index 000000000000..9b53dce87a23 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderModifiedLine.java @@ -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; + while((line = br.readLine()) != null) { + line = line.trim(); + count+=line.length(); + } + System.out.println(count); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSum.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSum.java new file mode 100644 index 000000000000..d04658e420c8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSum.java @@ -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; + while((line = br.readLine()) != null) { + String trimmed = line.trim(); + count+=trimmed.length(); + } + System.out.println(count); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSumLineReused.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSumLineReused.java new file mode 100644 index 000000000000..369771058f97 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSumLineReused.java @@ -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; + while((line = br.readLine()) != null) { + String trimmed = line.trim(); + count+=trimmed.length(); + } + System.out.println(count+":"+line); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFilterMapFlatMapArrayMapCollect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFilterMapFlatMapArrayMapCollect.java new file mode 100644 index 000000000000..b994def8f9c0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFilterMapFlatMapArrayMapCollect.java @@ -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 map) { + List result = new ArrayList<>(); + for(Map.Entry entry: map.entrySet()) { + if(entry.getKey().startsWith("x")) { + String[] arr = entry.getValue(); + for (String str : arr) { + str = str.trim(); + result.add(str); + } + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java b/java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java new file mode 100644 index 000000000000..1ffb8ed7afae --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java @@ -0,0 +1,6 @@ +class Test { + { + String s = "hello"; + Runnable r = () -> {Runnable rr = () -> System.out.println(s);}; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java.after b/java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java.after new file mode 100644 index 000000000000..bf51c648d5b8 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java.after @@ -0,0 +1,5 @@ +class Test { + { + Runnable r = () -> {Runnable rr = () -> System.out.println("hello");}; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.after.java b/java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.after.java new file mode 100644 index 000000000000..f8b362717c70 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.after.java @@ -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); + } + } +} diff --git a/java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.java b/java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.java new file mode 100644 index 000000000000..3d0a9a9e7523 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.java @@ -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(input.length); + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java index eb7b18ed748f..f7da07c33723 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java @@ -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")); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java index 6559b6bb6447..1bf326ee32c5 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java @@ -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); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexBuilder.java index 931177aca9b2..adc3c626a660 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexBuilder.java @@ -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 dirtyFilesHolder, OutputConsumer outputConsumer) throws ProjectBuildException, IOException { - final BackwardReferenceIndexWriter writer = BackwardReferenceIndexWriter.getInstance(); - if (writer != null) { - for (ModuleBuildTarget target : chunk.getTargets()) { - final Collection 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 files = dirtyFilesHolder.getRemovedFiles(target); + writer.processDeletedFiles(files); + } } } return null; diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java index 3e6ca58caacc..991fa515c800 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java @@ -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 rawOldSupers = myIndex.getHierarchyMap().get(classId); - Set oldSuperClasses = rawOldSupers == null ? null : new THashSet(rawOldSupers); + Set 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(rawOldSupers); + } for (LightRef.JavaLightClassRef superId: superIds) { if (oldSuperClasses == null || !oldSuperClasses.remove(superId)) { myIndex.getBackwardHierarchyMap().put(superId, classId); diff --git a/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt b/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt index 2cdaac81f565..accc05100e94 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt +++ b/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt @@ -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) { diff --git a/platform/core-api/src/com/intellij/openapi/editor/DocumentRunnable.java b/platform/core-api/src/com/intellij/openapi/editor/DocumentRunnable.java index 8b2133775564..e1b242090965 100644 --- a/platform/core-api/src/com/intellij/openapi/editor/DocumentRunnable.java +++ b/platform/core-api/src/com/intellij/openapi/editor/DocumentRunnable.java @@ -38,9 +38,4 @@ public abstract class DocumentRunnable implements Runnable { return myProject; } - public abstract static class IgnoreDocumentRunnable extends DocumentRunnable { - public IgnoreDocumentRunnable() { - super(null, null); - } - } } diff --git a/platform/core-api/src/com/intellij/usageView/UsageInfo.java b/platform/core-api/src/com/intellij/usageView/UsageInfo.java index 25cdc3d2b166..2c2f3dc3be0c 100644 --- a/platform/core-api/src/com/intellij/usageView/UsageInfo.java +++ b/platform/core-api/src/com/intellij/usageView/UsageInfo.java @@ -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) { diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/impl/ZipHandler.java b/platform/core-impl/src/com/intellij/openapi/vfs/impl/ZipHandler.java index 0363d8a1b8a3..8db15107dc1a 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/impl/ZipHandler.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/impl/ZipHandler.java @@ -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 createEntriesMap() throws IOException { - FileAccessorCache.Handle zipRef = getZipFileHandle(); - try { - ZipFile zip = zipRef.get(); + FileAccessorCache.Handle existingZipRef = getZipHandleForIteratingEntries(); - Map map = new ZipEntryMap(zip.size()); - map.put("", createRootEntry()); + if (existingZipRef == null) { + File file = getFile(); + ZipFile zipFile = new ZipFile(file); - Enumeration 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 getZipFileHandle() throws IOException { - FileAccessorCache.Handle handle = ourZipFileFileAccessorCache.get(this); + protected @Nullable FileAccessorCache.Handle getZipHandleForIteratingEntries() throws IOException { + return getCachedZipFileHandle(true); + } - if (getFile() == getFileToUse()) { // files are canonicalized + @NotNull + private Map buildEntryMapForZipFile(ZipFile zip) { + Map map = new ZipEntryMap(zip.size()); + map.put("", createRootEntry()); + + Enumeration entries = zip.entries(); + while (entries.hasMoreElements()) { + getOrCreate(entries.nextElement(), map, zip); + } + + return map; + } + + @Nullable + protected FileAccessorCache.Handle getCachedZipFileHandle(boolean createHandleIfNeeded) throws IOException { + FileAccessorCache.Handle 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 zipRef; try { - zipRef = getZipFileHandle(); + zipRef = getCachedZipFileHandle(true); } catch (RuntimeException ex) { Throwable cause = ex.getCause(); diff --git a/platform/credential-store/src/KeePassCredentialStore.kt b/platform/credential-store/src/KeePassCredentialStore.kt index f373d1fcfd9f..e7ac517a9984 100644 --- a/platform/credential-store/src/KeePassCredentialStore.kt +++ b/platform/credential-store/src/KeePassCredentialStore.kt @@ -41,7 +41,7 @@ internal class KeePassCredentialStore(keyToValue: Map, store: PasswordStorage) { diff --git a/platform/credential-store/src/PasswordSafeConfigurable.kt b/platform/credential-store/src/PasswordSafeConfigurable.kt index 89292531183d..e6ead52b6438 100644 --- a/platform/credential-store/src/PasswordSafeConfigurable.kt +++ b/platform/credential-store/src/PasswordSafeConfigurable.kt @@ -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("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 { - 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() 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 } \ No newline at end of file diff --git a/platform/credential-store/src/PasswordSafeImpl.kt b/platform/credential-store/src/PasswordSafeImpl.kt index ee8a53d9c3f1..cad093d65074 100644 --- a/platform/credential-store/src/PasswordSafeImpl.kt +++ b/platform/credential-store/src/PasswordSafeImpl.kt @@ -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 diff --git a/platform/credential-store/src/PasswordSafeSettings.java b/platform/credential-store/src/PasswordSafeSettings.java index 080f8429ff57..8121e3b3397d 100644 --- a/platform/credential-store/src/PasswordSafeSettings.java +++ b/platform/credential-store/src/PasswordSafeSettings.java @@ -28,7 +28,7 @@ import org.jetbrains.annotations.NotNull; public class PasswordSafeSettings implements PersistentStateComponent { public static final Topic 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 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; + *

+ * The listener interface for handling async {@link ChangeListManager} node models updating. + *

+ *

+ * When 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;
* moreover, when long duration update starts we should also trigger some action; + *

*/ public interface AsyncFilesManagerListener extends EventListener { diff --git a/platform/lang-api/src/com/intellij/codeInsight/hints/InlayParameterHintsProvider.kt b/platform/lang-api/src/com/intellij/codeInsight/hints/InlayParameterHintsProvider.kt index 5e2f842039e7..6d9dc91dd9bd 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/hints/InlayParameterHintsProvider.kt +++ b/platform/lang-api/src/com/intellij/codeInsight/hints/InlayParameterHintsProvider.kt @@ -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("com.intellij.parameterHintsProvider") +@ApiStatus.Experimental interface InlayParameterHintsProvider { - - fun getParameterHints(element: PsiElement): List { - return emptyList() - } - fun getMethodInfo(element: PsiElement): MethodInfo? { - return null - } - + /** + * Hints for params to be shown + */ + fun getParameterHints(element: PsiElement): List = 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 } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java index ce40d42eee2c..a0d2939c9cc9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java @@ -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) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java index 01869a0c205d..0c8d509ff8e5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java @@ -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> toUpdate = changedElements.get(document); if (toUpdate == null) { // The document has been changed, but psi hasn't diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hints/PopupActions.kt b/platform/lang-impl/src/com/intellij/codeInsight/hints/PopupActions.kt index aec74685d04e..1d4e224bd6ab 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hints/PopupActions.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/hints/PopupActions.kt @@ -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 } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index 26000ab1b7c5..4e3ddf82294b 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -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 diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/FormatterBasedIndentAdjuster.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/FormatterBasedIndentAdjuster.java index d800750409d6..cbd8da60ab39 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/FormatterBasedIndentAdjuster.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/FormatterBasedIndentAdjuster.java @@ -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); + })); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java index 879e761eab1c..5f76d4aa1631 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java @@ -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); diff --git a/platform/platform-api/src/com/intellij/ide/plugins/PluginReplacement.java b/platform/platform-api/src/com/intellij/ide/plugins/PluginReplacement.java new file mode 100644 index 000000000000..4b274a14c772 --- /dev/null +++ b/platform/platform-api/src/com/intellij/ide/plugins/PluginReplacement.java @@ -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. + *

+ * The implementation must be registered in plugin.xml of the plugin you want to replace: + *

+ * <extensions defaultExtensionNs="com.intellij">
+ *   <pluginReplacement implementation="qualified-class-name"/>
+ * </extensions>
+ * 
+ * + * @author nik + */ +public abstract class PluginReplacement implements PluginAware { + public static final ExtensionPointName 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 "'" + newPlugin.getName() + "' plugin is designed as a replacement for currently installed '" + oldPlugin.getName() + "' plugin.
Do you want to " + + "disable '" + oldPlugin.getName() + "' to avoid possible conflicts?"; + } + + @Override + public final void setPluginDescriptor(PluginDescriptor pluginDescriptor) { + myPluginDescriptor = pluginDescriptor; + } + + public final PluginDescriptor getOldPluginDescriptor() { + return myPluginDescriptor; + } + + public final String getNewPluginId() { + return myNewPluginId; + } +} diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/InstallPluginAction.java b/platform/platform-impl/src/com/intellij/ide/plugins/InstallPluginAction.java index 2b40400a35da..21600f113bd3 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/InstallPluginAction.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/InstallPluginAction.java @@ -156,7 +156,7 @@ public class InstallPluginAction extends AnAction implements DumbAware { } }; final List 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); diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstaller.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstaller.java index 4f6d75a9d47c..6deff1df4851 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstaller.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstaller.java @@ -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 pluginsToInstall, List allPlugins, + PluginManagerMain.PluginEnabler pluginEnabler, @NotNull ProgressIndicator indicator) { updateUrls(pluginsToInstall, indicator); Set 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 pluginsToInstall, List allPlugins, Set installedDependant, + PluginManagerMain.PluginEnabler pluginEnabler, @NotNull ProgressIndicator indicator) { List 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 pluginIds, List allPlugins, Set 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 toDisable = Ref.create(null); + Optional 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; diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java index 08ab7f1b8439..8188ae767b91 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java @@ -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 plugins, final List 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 plugins, + final List 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 disabled); + void disablePlugins(Set disabled); boolean isDisabled(PluginId pluginId); @@ -719,6 +730,13 @@ public abstract class PluginManagerMain implements Disposable { } } + @Override + public void disablePlugins(Set 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 disabled) { - pluginsModel.enableRows(disabled.toArray(new IdeaPluginDescriptor[disabled.size()]), true); + pluginsModel.enableRows(disabled.toArray(new IdeaPluginDescriptor[0]), true); + } + + @Override + public void disablePlugins(Set disabled) { + pluginsModel.enableRows(disabled.toArray(new IdeaPluginDescriptor[0]), false); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java index 03f10fbf6f4a..15a2b6a5b583 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java @@ -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 diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJRadioButtonUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJRadioButtonUI.java index 3fdf28bfb433..90a4d01efa86 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJRadioButtonUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJRadioButtonUI.java @@ -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); + } } diff --git a/platform/platform-impl/src/com/intellij/notification/EventLogConsole.java b/platform/platform-impl/src/com/intellij/notification/EventLogConsole.java index 0790a2851f66..1e3542180493 100644 --- a/platform/platform-impl/src/com/intellij/notification/EventLogConsole.java +++ b/platform/platform-impl/src/com/intellij/notification/EventLogConsole.java @@ -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, diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java index d7773879c448..e6e3e259b495 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java @@ -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 ourEventStack = new Stack<>(); // guarded by RUN_LOCK - private static final EventDispatcher 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; diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java index 609204ff1942..559d9dd049b6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java @@ -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 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 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 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 future = ourExecutor.submit(() -> { - Ref 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 scheduleLoading() { + PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(myProject); + long startStamp = myEditor.getDocument().getModificationStamp(); + return ourExecutor.submit(() -> { + Ref 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 resultInTimeOrNull(Future 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; } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorComponent.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorComponent.java index ba10f60288bb..8b72201801f5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorComponent.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorComponent.java @@ -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 diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java index e952ec52758c..9e0b99a0a4e9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java @@ -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 diff --git a/platform/platform-impl/src/com/intellij/openapi/options/TabbedConfigurable.java b/platform/platform-impl/src/com/intellij/openapi/options/TabbedConfigurable.java index 217339f748f0..59cde1bfc0e9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/TabbedConfigurable.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/TabbedConfigurable.java @@ -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 { +public abstract class TabbedConfigurable extends CompositeConfigurable implements Configurable.NoScroll, + Configurable.NoMargin { protected TabbedPaneWrapper myTabbedPane; private final Disposable myParentDisposable; @@ -38,13 +41,14 @@ public abstract class TabbedConfigurable extends CompositeConfigurable() { @Override public JComponent compute() { diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiserDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiserDialog.java index 2b049a3d1589..f2ffcf6f293e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiserDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiserDialog.java @@ -94,7 +94,7 @@ public class PluginsAdvertiserDialog extends DialogWrapper { } if (!nodes.isEmpty()) { try { - PluginManagerMain.downloadPlugins(nodes, myAllPlugins, notifyRunnable, null); + PluginManagerMain.downloadPlugins(nodes, myAllPlugins, notifyRunnable, pluginHelper, null); } catch (IOException e) { LOG.error(e); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java index 9eceb307cfd5..4c5c3023d062 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java @@ -45,6 +45,7 @@ import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.*; +import java.util.zip.ZipFile; /** * @author max @@ -56,7 +57,7 @@ public class JarHandler extends ZipHandler { private static final int FS_TIME_RESOLUTION = 2000; private final JarFileSystemImpl myFileSystem; - private volatile File myFileWithMirrorResolved; + private volatile File myFileWithMirrorResolved; // field is reflectively referenced in tests public JarHandler(@NotNull String path) { super(path); @@ -78,6 +79,10 @@ public class JarHandler extends ZipHandler { return fileWithMirrorResolved; } + protected @Nullable FileAccessorCache.Handle getZipHandleForIteratingEntries() throws IOException { + return getCachedZipFileHandle(!myFileSystem.isMakeCopyOfJar(getFile()) || myFileWithMirrorResolved != null); + } + private File getMirrorFile(@NotNull File originalFile) { if (!myFileSystem.isMakeCopyOfJar(originalFile)) return originalFile; diff --git a/platform/platform-impl/src/com/intellij/ui/layout/LayoutBuilder.kt b/platform/platform-impl/src/com/intellij/ui/layout/LayoutBuilder.kt index 2fbb07fd3b20..db152ecb0ec9 100644 --- a/platform/platform-impl/src/com/intellij/ui/layout/LayoutBuilder.kt +++ b/platform/platform-impl/src/com/intellij/ui/layout/LayoutBuilder.kt @@ -16,6 +16,7 @@ package com.intellij.ui.layout import com.intellij.ui.components.Label +import java.awt.event.ActionListener import javax.swing.ButtonGroup import javax.swing.JLabel @@ -38,4 +39,15 @@ class LayoutBuilder(val `$`: LayoutBuilderImpl, val buttonGroup: ButtonGroup? = inline fun buttonGroup(init: LayoutBuilder.() -> Unit) { LayoutBuilder(`$`, ButtonGroup()).init() } + + inline fun buttonGroup(crossinline elementActionListener: () -> Unit, init: LayoutBuilder.() -> Unit): ButtonGroup { + val group = ButtonGroup() + LayoutBuilder(`$`, group).init() + + val listener = ActionListener { elementActionListener() } + for (button in group.elements) { + button.addActionListener(listener) + } + return group + } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ui/layout/MigLayoutBuilder.kt b/platform/platform-impl/src/com/intellij/ui/layout/MigLayoutBuilder.kt index c9b2d09fc8dd..e2c4b80395d4 100644 --- a/platform/platform-impl/src/com/intellij/ui/layout/MigLayoutBuilder.kt +++ b/platform/platform-impl/src/com/intellij/ui/layout/MigLayoutBuilder.kt @@ -22,6 +22,7 @@ import com.intellij.openapi.actionSystem.ToggleAction import com.intellij.openapi.project.DumbAware import com.intellij.openapi.ui.OnePixelDivider import com.intellij.ui.SeparatorComponent +import com.intellij.ui.components.Label import com.intellij.ui.components.noteComponent import com.intellij.util.SmartList import net.miginfocom.layout.* @@ -40,14 +41,14 @@ internal class MigLayoutBuilder : LayoutBuilderImpl { private val componentConstraints: MutableMap = SmartHashMap() - override fun newRow(label: JLabel?, buttonGroup: ButtonGroup?, separated: Boolean): Row { + override fun newRow(label: JLabel?, buttonGroup: ButtonGroup?, separated: Boolean, indented: Boolean): Row { if (separated) { - val row = MigLayoutRow(componentConstraints, noGrid = true, separated = true) + val row = MigLayoutRow(componentConstraints, this, noGrid = true, separated = true) rows.add(row) row.apply { SeparatorComponent(0, OnePixelDivider.BACKGROUND, null)() } } - val row = MigLayoutRow(componentConstraints, label != null, buttonGroup = buttonGroup) + val row = MigLayoutRow(componentConstraints, this, label != null, buttonGroup = buttonGroup, indented = indented) rows.add(row) label?.let { row.apply { label() } } @@ -59,13 +60,13 @@ internal class MigLayoutBuilder : LayoutBuilderImpl { // add empty row as top gap newRow() - val row = MigLayoutRow(componentConstraints, noGrid = true) + val row = MigLayoutRow(componentConstraints, this, noGrid = true) rows.add(row) row.apply { noteComponent(text)() } } override fun build(container: Container, layoutConstraints: Array) { - val labeled = rows.firstOrNull(MigLayoutRow::labeled) != null + val labeled = rows.firstOrNull({ it.labeled && !it.indented }) != null var gapTop = -1 val lc = c() @@ -77,6 +78,8 @@ internal class MigLayoutBuilder : LayoutBuilderImpl { lc.apply(layoutConstraints) } + lc.noVisualPadding() + container.layout = MigLayout(lc) val noGrid = layoutConstraints.contains(LCFlags.noGrid) @@ -124,12 +127,18 @@ internal class MigLayoutBuilder : LayoutBuilderImpl { } else { var isSkippableComponent = true - if (component === row.components.first() && labeled) { - if (row.labeled) { - isSkippableComponent = false + if (component === row.components.first()) { + if (row.indented) { + cc.horizontal.gapBefore = gapToBoundSize(HORIZONTAL_GAP * 3, true) } - else { - cc.skip() + + if (labeled) { + if (row.labeled) { + isSkippableComponent = false + } + else { + cc.skip() + } } } @@ -138,7 +147,10 @@ internal class MigLayoutBuilder : LayoutBuilderImpl { isSplitRequired = false cc.split() } - cc.horizontal.gapAfter = gapToBoundSize(HORIZONTAL_GAP * 2, true) + + if (component !== lastComponent) { + cc.horizontal.gapAfter = gapToBoundSize(HORIZONTAL_GAP * 2, true) + } } } @@ -166,20 +178,39 @@ private fun addGrowIfNeed(cc: CC, component: Component) { } } -private class MigLayoutRow(private val componentConstraints: MutableMap, val labeled: Boolean = false, val noGrid: Boolean = false, private val buttonGroup: ButtonGroup? = null, val separated: Boolean = false) : Row() { +private class MigLayoutRow(private val componentConstraints: MutableMap, + private val builder: MigLayoutBuilder, + val labeled: Boolean = false, + val noGrid: Boolean = false, + private val buttonGroup: ButtonGroup? = null, + val separated: Boolean = false, + val indented: Boolean = false) : Row() { val components = SmartList() var rightIndex = Int.MAX_VALUE - override operator fun JComponent.invoke(vararg constraints: CCFlags, gapLeft: Int) { - addComponent(this, constraints, gapLeft = gapLeft) + override var enabled: Boolean = true + get() = field + set(value) { + if (field == value) { + return + } + + field = value + for (c in components) { + c.isEnabled = value + } + } + + override operator fun JComponent.invoke(vararg constraints: CCFlags, gapLeft: Int, growPolicy: GrowPolicy?) { + addComponent(this, constraints, gapLeft = gapLeft, growPolicy = growPolicy) } - private fun addComponent(component: Component, constraints: Array, gapLeft: Int) { + private fun addComponent(component: Component, constraints: Array, gapLeft: Int, growPolicy: GrowPolicy?) { if (buttonGroup != null && component is JToggleButton) { buttonGroup.add(component) } - createComponentConstraints(constraints, gapLeft = gapLeft)?.let { + createComponentConstraints(constraints, gapLeft = gapLeft, growPolicy = growPolicy)?.let { componentConstraints.put(component, it) } components.add(component) @@ -191,6 +222,12 @@ private class MigLayoutRow(private val componentConstraints: MutableMap Unit): Row { + val row = builder.newRow(Label(label), indented = true) + row.init() + return row + } } private fun createComponentConstraints(constraints: Array? = null, @@ -198,7 +235,8 @@ private fun createComponentConstraints(constraints: Array? = null, gapAfter: Int = 0, gapTop: Int = 0, gapBottom: Int = 0, - split: Int = -1): CC? { + split: Int = -1, + growPolicy: GrowPolicy?): CC? { var _cc = constraints?.create() fun cc(): CC { if (_cc == null) { @@ -224,6 +262,12 @@ private fun createComponentConstraints(constraints: Array? = null, if (split != -1) { cc().split = split } + + if (growPolicy == GrowPolicy.SHORT_TEXT) { +// cc().minWidth("210") + cc().maxWidth("210") + } + return _cc } diff --git a/platform/platform-impl/src/com/intellij/ui/layout/Row.kt b/platform/platform-impl/src/com/intellij/ui/layout/Row.kt index 012acdb5efa4..9153addf4ed5 100644 --- a/platform/platform-impl/src/com/intellij/ui/layout/Row.kt +++ b/platform/platform-impl/src/com/intellij/ui/layout/Row.kt @@ -29,6 +29,8 @@ import javax.swing.JComponent import javax.swing.JLabel abstract class Row() { + abstract var enabled: Boolean + fun label(text: String, gapLeft: Int = 0, style: ComponentStyle? = null, fontColor: FontColor? = null, bold: Boolean = false) { Label(text, style, fontColor, bold)(gapLeft = gapLeft) } @@ -55,7 +57,7 @@ abstract class Row() { panel(*constraints) } - abstract operator fun JComponent.invoke(vararg constraints: CCFlags, gapLeft: Int = 0) + abstract operator fun JComponent.invoke(vararg constraints: CCFlags, gapLeft: Int = 0, growPolicy: GrowPolicy? = null) inline fun right(init: Row.() -> Unit) { alignRight() @@ -64,9 +66,7 @@ abstract class Row() { protected abstract fun alignRight() - @Deprecated(message = "Nested row is prohibited", level = DeprecationLevel.ERROR) - fun row(label: String, init: Row.() -> Unit) { - } + abstract fun row(label: String, init: Row.() -> Unit): Row @Deprecated(message = "Nested row is prohibited", level = DeprecationLevel.ERROR) fun row(label: JLabel? = null, init: Row.() -> Unit) { @@ -75,4 +75,8 @@ abstract class Row() { @Deprecated(message = "Nested noteRow is prohibited", level = DeprecationLevel.ERROR) fun noteRow(text: String) { } +} + +enum class GrowPolicy { + SHORT_TEXT } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ui/layout/layoutImpl.kt b/platform/platform-impl/src/com/intellij/ui/layout/layoutImpl.kt index a0aff8543335..f53366913449 100644 --- a/platform/platform-impl/src/com/intellij/ui/layout/layoutImpl.kt +++ b/platform/platform-impl/src/com/intellij/ui/layout/layoutImpl.kt @@ -32,7 +32,7 @@ fun createLayoutBuilder() = LayoutBuilder(MigLayoutBuilder()) // "When a protected member is accessed from an inline function, a public accessor method is created to provide an access to that protected member from the outside of the class where the function will be inlined to." // (https://youtrack.jetbrains.com/issue/KT-12215) interface LayoutBuilderImpl { - fun newRow(label: JLabel? = null, buttonGroup: ButtonGroup? = null, separated: Boolean = false): Row + fun newRow(label: JLabel? = null, buttonGroup: ButtonGroup? = null, separated: Boolean = false, indented: Boolean = false): Row fun build(container: Container, layoutConstraints: Array) diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index e7acfaf1e55b..397ae57572b9 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -1034,6 +1034,7 @@ predefined.scope.production.name=Production plugin.manager.dependencies.detected.title=Plugin Dependencies Detected plugin.manager.dependencies.detected.message=The plugin you want to install requires other plugin{0, choice, 1#|2#s} ({1}) which have to be installed as well. Proceed? plugin.manager.optional.dependencies.detected.message=The plugin you want to install optionally requires other plugin{0, choice, 1#|2#s} ({1}). Should those be installed as well? +plugin.manager.obsolete.plugins.detected.title=Obsolete Plugins Detected message.server.no.licenses=No suitable licenses left on the license server title.server.no.licenses=No Licenses on Server message.server.not.available=Unable to contact license server diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index 8733150897a1..125e5325347d 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -219,6 +219,8 @@ + + diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/JarFileSystemTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/JarFileSystemTest.java index 2a8bf039ebfa..462800fad254 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/JarFileSystemTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/JarFileSystemTest.java @@ -18,8 +18,11 @@ package com.intellij.openapi.vfs.local; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.io.FileAttributes; import com.intellij.openapi.util.io.IoTestUtil; import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.impl.jar.JarFileSystemImpl; +import com.intellij.openapi.vfs.impl.jar.JarHandler; import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem; import com.intellij.openapi.vfs.newvfs.BulkFileListener; import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent; @@ -32,6 +35,7 @@ import org.junit.Test; import java.io.File; import java.io.IOException; +import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.util.List; import java.util.jar.JarFile; @@ -117,6 +121,23 @@ public class JarFileSystemTest extends BareTestFixtureTestCase { assertContent(newEntry, "some text"); } + @Test + public void testJarHandlerDoNotCreateCopyWhenListingArchive() throws Exception { + File jar = IoTestUtil.createTestJar(); + JarHandler handler = new JarHandler(jar.getPath()); + FileAttributes attributes = handler.getAttributes(JarFile.MANIFEST_NAME); + assertTrue(attributes != null); + assertTrue(attributes.length == 0); + assertTrue(attributes.lastModified == jar.lastModified()); + + if (((JarFileSystemImpl)JarFileSystem.getInstance()).isMakeCopyOfJar(jar)) { + // for performance reasons we create file copy on windows when we read contents and have the handle open to the copy + Field resolved = handler.getClass().getDeclaredField("myFileWithMirrorResolved"); + resolved.setAccessible(true); + assertTrue(resolved.get(handler) == null); + } + } + @Test public void testInvalidJar() { String jarPath = PathManagerEx.getTestDataPath() + "/vfs/maven-toolchain-1.0.jar"; diff --git a/platform/platform-tests/testSrc/org/jetbrains/concurrency/AsyncPromiseTest.kt b/platform/platform-tests/testSrc/org/jetbrains/concurrency/AsyncPromiseTest.kt index 2aead477e5fe..aedb1530838b 100644 --- a/platform/platform-tests/testSrc/org/jetbrains/concurrency/AsyncPromiseTest.kt +++ b/platform/platform-tests/testSrc/org/jetbrains/concurrency/AsyncPromiseTest.kt @@ -66,9 +66,9 @@ class AsyncPromiseTest { fun blockingGet() { val promise = AsyncPromise() assertConcurrent( - { assertThat(promise.blockingGet(100)).isEqualTo("test") }, + { assertThat(promise.blockingGet(1000)).isEqualTo("test") }, { - Thread.sleep(80) + Thread.sleep(100) promise.setResult("test") }) } @@ -79,7 +79,7 @@ class AsyncPromiseTest { assertConcurrent( { assertThatThrownBy { promise.blockingGet(100) }.isInstanceOf(TimeoutException::class.java) }, { - Thread.sleep(200) + Thread.sleep(1000) promise.setResult("test") }) } @@ -142,7 +142,7 @@ fun assertConcurrent(vararg runnables: () -> Any?, maxTimeoutSeconds: Int = 5) { } // wait until all threads are ready - assertThat(allExecutorThreadsReady.await((runnables.size * 10).toLong(), TimeUnit.MILLISECONDS)).isTrue() + assertThat(allExecutorThreadsReady.await((runnables.size * 1000).toLong(), TimeUnit.MILLISECONDS)).isTrue() // start all test runners afterInitBlocker.countDown() assertThat(allDone.await(maxTimeoutSeconds.toLong(), TimeUnit.SECONDS)).isTrue() diff --git a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestStatusLine.java b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestStatusLine.java index ee296686647c..938fb80a7555 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestStatusLine.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestStatusLine.java @@ -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. @@ -67,7 +67,7 @@ public class TestStatusLine extends JPanel { return; } String result = ""; - if (finishedTestsCount == testsTotal) { + if (finishedTestsCount == testsTotal || testsTotal < 0) { if (testsTotal > 1 && (failuresCount == 0 && ignoredTestsCount == 0 || failuresCount == testsTotal || ignoredTestsCount == testsTotal)) { result = "All "; } @@ -76,7 +76,7 @@ public class TestStatusLine extends JPanel { result = "Stopped. " + finishedTestsCount + " of "; } - result += getTestsTotalMessage(testsTotal); + result += getTestsTotalMessage(testsTotal > 0 ? testsTotal : finishedTestsCount); if (failuresCount == 0 && ignoredTestsCount == 0) { myState.append(result + " passed"); diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 6449f11f07b5..12201700c919 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -743,9 +743,6 @@ database.scrollable.result.sets=true database.src_storage.enabled.description=Enables database sources storage database.src_storage.enabled.restartRequired=true database.src_storage.enabled=false -database.src_storage.writable.description=Enables database sources storage modification -database.src_storage.writable.restartRequired=true -database.src_storage.writable=false git.status.write=true git.blocking.read=true diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 07f945c27351..7d5ddd12d8bd 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -1577,6 +1577,10 @@ public class UIUtil { sb.append(Integer.toHexString(color.getBlue())); } + public static void drawDottedRectangle(Graphics g, Rectangle r) { + drawDottedRectangle(g, r.x, r.y, r.x + r.width, r.y + r.height); + } + /** * @param g graphics. * @param x top left X coordinate. diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java index 9bcb95c09861..aa7ba1c3c922 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java @@ -58,6 +58,7 @@ import com.intellij.util.Function; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcsUtil.VcsUtil; +import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.CalledInAwt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -241,9 +242,9 @@ public class ApplyPatchAction extends DumbAwareAction { @Override public boolean value(MergeTool.MergeViewer viewer) { int result = Messages.showYesNoCancelDialog(viewer.getComponent().getRootPane(), - "Would you like to (A)bort&Rollback applying patch action or (S)kip this file?", - "Close Merge", - "_Abort", "_Skip", "Cancel", Messages.getQuestionIcon()); + XmlStringUtil.wrapInHtml( + "Would you like to Abort&Rollback applying patch action or Skip this file?"), + "Close Merge", "_Abort", "_Skip", "Cancel", Messages.getQuestionIcon()); if (result == Messages.YES) { applyPatchStatusReference.set(ApplyPatchStatus.ABORT); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java index fda55327135a..3c759d4bb84f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java @@ -93,7 +93,7 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { @Override public XLineBreakpointType[] getLineBreakpointTypes() { if (myLineBreakpointTypes == null) { - myLineBreakpointTypes = XBreakpointUtil.getBreakpointTypes().select(XLineBreakpointType.class).toArray(XLineBreakpointType[]::new); + myLineBreakpointTypes = XBreakpointUtil.breakpointTypes().select(XLineBreakpointType.class).toArray(XLineBreakpointType[]::new); } return myLineBreakpointTypes; } @@ -289,7 +289,7 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { @Override public T findBreakpointType(@NotNull Class typeClass) { if (myBreakpointTypeByClass == null) { - myBreakpointTypeByClass = XBreakpointUtil.getBreakpointTypes().toMap(XBreakpointType::getClass, t -> t); + myBreakpointTypeByClass = XBreakpointUtil.breakpointTypes().toMap(XBreakpointType::getClass, t -> t); } XBreakpointType type = myBreakpointTypeByClass.get(typeClass); //noinspection unchecked diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java index 3329d22eebd1..63a63b84b54f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java @@ -75,7 +75,7 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta HttpVirtualFileListener httpVirtualFileListener = this::updateBreakpointInFile; HttpFileSystem.getInstance().addFileListener(httpVirtualFileListener, project); } - XBreakpointUtil.getBreakpointTypes().forEach(this::addDefaultBreakpoint); + XBreakpointUtil.breakpointTypes().forEach(this::addDefaultBreakpoint); } } @@ -397,7 +397,7 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta ApplicationManager.getApplication().runReadAction(() -> { state.getDefaultBreakpoints().forEach(breakpointState -> loadBreakpoint(breakpointState, true)); - XBreakpointUtil.getBreakpointTypes().remove(myDefaultBreakpoints::containsKey).forEach(this::addDefaultBreakpoint); + XBreakpointUtil.breakpointTypes().remove(myDefaultBreakpoints::containsKey).forEach(this::addDefaultBreakpoint); myBreakpoints.values().forEach(this::doRemoveBreakpoint); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointUtil.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointUtil.java index 32b23e448ec9..b07d81d0c356 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointUtil.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointUtil.java @@ -64,10 +64,10 @@ public class XBreakpointUtil { @Nullable public static XBreakpointType findType(@NotNull @NonNls String id) { - return getBreakpointTypes().filter(breakpointType -> id.equals(breakpointType.getId())).findFirst().orElse(null); + return breakpointTypes().filter(breakpointType -> id.equals(breakpointType.getId())).findFirst().orElse(null); } - public static StreamEx getBreakpointTypes() { + public static StreamEx breakpointTypes() { return StreamEx.of(XBreakpointType.EXTENSION_POINT_NAME.getExtensions()); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsDialog.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsDialog.java index b62e50ff697f..720340dee108 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsDialog.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsDialog.java @@ -306,11 +306,10 @@ public class BreakpointsDialog extends DialogWrapper { } }.registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE).getShortcutSet(), tree, myDisposable); - DefaultActionGroup breakpointTypes = new DefaultActionGroup(); - XBreakpointUtil.getBreakpointTypes() + DefaultActionGroup breakpointTypes = XBreakpointUtil.breakpointTypes() .filter(XBreakpointType::isAddBreakpointButtonVisible) .map(AddXBreakpointAction::new) - .forEach(breakpointTypes::add); + .toListAndThen(DefaultActionGroup::new); ToolbarDecorator decorator = ToolbarDecorator.createDecorator(tree). setAddAction(new AnActionButtonRunnable() { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/grouping/XBreakpointTypeGroup.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/grouping/XBreakpointTypeGroup.java index 1c490c7a4ce7..6eda5e3e026d 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/grouping/XBreakpointTypeGroup.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/grouping/XBreakpointTypeGroup.java @@ -74,6 +74,6 @@ public class XBreakpointTypeGroup extends XBreakpointGroup { } private static int indexOfType(XBreakpointType type) { - return (int)XBreakpointUtil.getBreakpointTypes().indexOf(type).orElse(-1); + return (int)XBreakpointUtil.breakpointTypes().indexOf(type).orElse(-1); } } diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java index 85d35c0d14f9..9d133148b080 100644 --- a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java +++ b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java @@ -438,15 +438,14 @@ public class XDebuggerTestUtil { @NotNull final XBreakpointProperties properties) { XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); Ref breakpoint = Ref.create(null); - XBreakpointUtil.getBreakpointTypes().select(exceptionType).findFirst().ifPresent(type -> { - final T breakpointType = exceptionType.cast(type); + XBreakpointUtil.breakpointTypes().select(exceptionType).findFirst().ifPresent(type -> new WriteAction() { @Override protected void run(@NotNull Result result) throws Throwable { - breakpoint.set(breakpointManager.addBreakpoint(breakpointType, properties)); + breakpoint.set(breakpointManager.addBreakpoint(type, properties)); } - }.execute(); - }); + }.execute() + ); return breakpoint.get(); } diff --git a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java index 2681d5da54de..302110e6ef31 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java +++ b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java @@ -115,7 +115,15 @@ public class CoverageDataManagerImpl extends CoverageDataManager { chooseSuitesBundle(myCurrentSuitesBundle); } }); - addSuiteListener(new CoverageViewSuiteListener(this, myProject), myProject); + final CoverageViewSuiteListener coverageViewListener = createCoverageViewListener(); + if (coverageViewListener != null) { + addSuiteListener(coverageViewListener, myProject); + } + } + + @Nullable + protected CoverageViewSuiteListener createCoverageViewListener() { + return new CoverageViewSuiteListener(this, myProject); } diff --git a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java index b2f721479513..74e7cc0066f5 100644 --- a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java +++ b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java @@ -840,7 +840,9 @@ public class GitHistoryUtils { Collection refsInRecord = parseRefs(record.getRefs(), commit.getId(), factory, root); for (VcsRef ref : refsInRecord) { if (!refs.add(ref)) { - LOG.error("Adding duplicate element to the set"); + // relying on the fact that intersection method puts elements of the first argument into the result + VcsRef otherRef = ContainerUtil.getFirstItem(ContainerUtil.intersection(refs, Collections.singleton(ref))); + LOG.error("Adding duplicate element " + ref + " to the set containing " + otherRef); } } return commit; diff --git a/plugins/google-app-engine/resources/META-INF/google-app-engine-plugin.xml b/plugins/google-app-engine/resources/META-INF/google-app-engine-plugin.xml index 2d78b4f4cb0f..abe4b2d6ecf6 100644 --- a/plugins/google-app-engine/resources/META-INF/google-app-engine-plugin.xml +++ b/plugins/google-app-engine/resources/META-INF/google-app-engine-plugin.xml @@ -25,6 +25,8 @@ implementationClass="com.intellij.appengine.inspections.AppEngineForbiddenCodeInspection"/> + + diff --git a/plugins/google-app-engine/source/com/intellij/appengine/converter/AppEnginePluginReplacement.java b/plugins/google-app-engine/source/com/intellij/appengine/converter/AppEnginePluginReplacement.java new file mode 100644 index 000000000000..31dc1a4cb633 --- /dev/null +++ b/plugins/google-app-engine/source/com/intellij/appengine/converter/AppEnginePluginReplacement.java @@ -0,0 +1,27 @@ +/* + * 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.appengine.converter; + +import com.intellij.ide.plugins.PluginReplacement; + +/** + * @author nik + */ +public class AppEnginePluginReplacement extends PluginReplacement { + public AppEnginePluginReplacement() { + super("com.google.gct.core"); + } +} diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java index 1d10271353da..f426ccc4d1a1 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java @@ -24,10 +24,8 @@ import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.process.ProcessWaitFor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vfs.CharsetToolkit; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.concurrency.AppExecutorUtil; import com.intellij.util.containers.HashMap; @@ -129,24 +127,13 @@ public class LocalTerminalDirectRunner extends AbstractTerminalRunner { + private static final Logger LOG = Logger.getInstance(TerminalProjectOptionsProvider.class); + + private State myState = new State(); + private final Project myProject; + + public TerminalProjectOptionsProvider(Project project) {myProject = project;} + + + public static TerminalProjectOptionsProvider getInstance(@NotNull Project project) { + return ServiceManager.getService(project, TerminalProjectOptionsProvider.class); + } + + @Override + public State getState() { + return myState; + } + + @Override + public void loadState(State state) { + setShellPath(state.myShellPath); + myState.myStartingDirectory = state.myStartingDirectory; + } + + + public static class State { + public String myShellPath = null; + public String myStartingDirectory = null; + } + + public String getShellPath() { + if (myState.myShellPath != null) { + return myState.myShellPath; + } else { + return getDefaultShellPath(); + } + } + + + public void setShellPath(String shellPath) { + if (isShellPathDefault(shellPath) || StringUtil.isEmpty(shellPath)) { + myState.myShellPath = null; + } else { + myState.myShellPath = shellPath; + } + } + + + public void setStartingDirectory(String startingDirectory) { + if (isStartingDirectoryDefault(startingDirectory) || StringUtil.isEmpty(startingDirectory)) { + myState.myStartingDirectory = null; + } else { + myState.myStartingDirectory = startingDirectory; + } + } + + public boolean isShellPathDefault(String shellPath) { + return StringUtil.equals(shellPath, getDefaultShellPath()); + } + + public boolean isStartingDirectoryDefault(String startingDirectory) { + return StringUtil.equals(startingDirectory, getDefaultStartingDirectory()); + } + + public String getStartingDirectory() { + if (myState.myStartingDirectory != null) { + return myState.myStartingDirectory; + } + else { + return getDefaultStartingDirectory(); + } + } + + + private static String getDefaultShellPath() { + String shell = System.getenv("SHELL"); + + if (shell != null && new File(shell).canExecute()) { + return shell; + } + + if (SystemInfo.isUnix) { + if (new File("/bin/bash").exists()) { + return "/bin/bash"; + } + else { + return "/bin/sh"; + } + } + else { + return "cmd.exe"; + } + } + + public String getDefaultStartingDirectory() { + String directory = null; + for (LocalTerminalCustomizer customizer : LocalTerminalCustomizer.EP_NAME.getExtensions()) { + try { + + if (directory == null) { + directory = customizer.getDefaultFolder(); + } + } + catch (Exception e) { + LOG.error("Exception during getting default folder", e); + } + } + + return currentProjectFolder(); + } + + + private String currentProjectFolder() { + final ProjectRootManager projectRootManager = ProjectRootManager.getInstance(myProject); + + final VirtualFile[] roots = projectRootManager.getContentRoots(); + if (roots.length == 1) { + roots[0].getCanonicalPath(); + } + final VirtualFile baseDir = myProject.getBaseDir(); + return baseDir == null ? null : baseDir.getCanonicalPath(); + } +} + diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.form b/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.form index af3c82b03bad..f8963c843dd9 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.form +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.form @@ -3,12 +3,12 @@ - + - + @@ -19,7 +19,12 @@ - + + + + + + @@ -36,37 +41,30 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - + @@ -74,23 +72,37 @@ - + + - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + @@ -110,121 +122,144 @@ - - - - - - - - - - - + + - + - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.java index 66c0da8664de..1ae6c15aabb9 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.java +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.java @@ -19,10 +19,15 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.ui.TextComponentAccessor; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Comparing; +import com.intellij.ui.DocumentAdapter; +import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.components.JBCheckBox; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import javax.swing.event.DocumentEvent; +import java.awt.*; +import java.util.Arrays; /** * @author traff @@ -38,27 +43,61 @@ public class TerminalSettingsPanel { private JBCheckBox myCopyOnSelectionCheckBox; private JBCheckBox myOverrideIdeShortcuts; private JBCheckBox myShellIntegration; + private TextFieldWithBrowseButton myStartDirectoryField; + private JPanel myProjectSettingsPanel; + private JPanel myGlobalSettingsPanel; private TerminalOptionsProvider myOptionsProvider; + private TerminalProjectOptionsProvider myProjectOptionsProvider; - public JComponent createPanel(@NotNull TerminalOptionsProvider provider) { + public JComponent createPanel(@NotNull TerminalOptionsProvider provider, @NotNull TerminalProjectOptionsProvider projectOptionsProvider) { myOptionsProvider = provider; + myProjectOptionsProvider = projectOptionsProvider; + + myProjectSettingsPanel.setBorder(IdeBorderFactory.createTitledBorder("Project settings")); + myGlobalSettingsPanel.setBorder(IdeBorderFactory.createTitledBorder("Application settings")); FileChooserDescriptor fileChooserDescriptor = new FileChooserDescriptor(true, false, false, false, false, false); myShellPathField.addBrowseFolderListener( "", - "Shell Executable Path", + "Shell executable path", null, fileChooserDescriptor, - TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT, - false - ); + TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT); + + fileChooserDescriptor = new FileChooserDescriptor(false, true, false, false, false, false); + + myStartDirectoryField.addBrowseFolderListener( + "", + "Starting directory", + null, + fileChooserDescriptor, + TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT); + + myShellPathField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + myShellPathField + .getTextField().setForeground(myProjectOptionsProvider.isShellPathDefault(myShellPathField.getText()) ? + getDefaultValueColor() : getChangedValueColor()); + } + }); + + myStartDirectoryField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + myStartDirectoryField + .getTextField().setForeground(myProjectOptionsProvider.isStartingDirectoryDefault(myStartDirectoryField.getText()) ? + getDefaultValueColor() : getChangedValueColor()); + } + }); return myWholePanel; } public boolean isModified() { - return !Comparing.equal(myShellPathField.getText(), myOptionsProvider.getShellPath()) + return !Comparing.equal(myShellPathField.getText(), myProjectOptionsProvider.getShellPath()) + || !Comparing.equal(myStartDirectoryField.getText(), myProjectOptionsProvider.getStartingDirectory()) || !Comparing.equal(myTabNameTextField.getText(), myOptionsProvider.getTabName()) || (myCloseSessionCheckBox.isSelected() != myOptionsProvider.closeSessionOnLogout()) || (myMouseReportCheckBox.isSelected() != myOptionsProvider.enableMouseReporting()) @@ -71,7 +110,8 @@ public class TerminalSettingsPanel { } public void apply() { - myOptionsProvider.setShellPath(myShellPathField.getText()); + myProjectOptionsProvider.setShellPath(myShellPathField.getText()); + myProjectOptionsProvider.setStartingDirectory(myStartDirectoryField.getText()); myOptionsProvider.setTabName(myTabNameTextField.getText()); myOptionsProvider.setCloseSessionOnLogout(myCloseSessionCheckBox.isSelected()); myOptionsProvider.setReportMouse(myMouseReportCheckBox.isSelected()); @@ -83,7 +123,8 @@ public class TerminalSettingsPanel { } public void reset() { - myShellPathField.setText(myOptionsProvider.getShellPath()); + myShellPathField.setText(myProjectOptionsProvider.getShellPath()); + myStartDirectoryField.setText(myProjectOptionsProvider.getStartingDirectory()); myTabNameTextField.setText(myOptionsProvider.getTabName()); myCloseSessionCheckBox.setSelected(myOptionsProvider.closeSessionOnLogout()); myMouseReportCheckBox.setSelected(myOptionsProvider.enableMouseReporting()); @@ -93,4 +134,26 @@ public class TerminalSettingsPanel { myOverrideIdeShortcuts.setSelected(myOptionsProvider.overrideIdeShortcuts()); myShellIntegration.setSelected(myOptionsProvider.shellIntegration()); } + + public Color getDefaultValueColor() { + return findColorByKey("TextField.inactiveForeground", "nimbusDisabledText"); + } + + @NotNull + private static Color findColorByKey(String... colorKeys) { + Color c = null; + for (String key : colorKeys) { + c = UIManager.getColor(key); + if (c != null) { + break; + } + } + + assert c != null : "Can't find color for keys " + Arrays.toString(colorKeys); + return c; + } + + public Color getChangedValueColor() { + return findColorByKey("TextField.foreground"); + } } diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/transport/ServerModeDebuggerTransport.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/transport/ServerModeDebuggerTransport.java index 74164e4f6f92..1494dea1614f 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/transport/ServerModeDebuggerTransport.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/transport/ServerModeDebuggerTransport.java @@ -39,6 +39,7 @@ public class ServerModeDebuggerTransport extends BaseDebuggerTransport { myServerSocket.setSoTimeout(myConnectionTimeout); Socket socket = myServerSocket.accept(); + myConnected = true; try { myDebuggerReader = new DebuggerReader(myDebugger, socket.getInputStream()); } diff --git a/resources-en/src/inspectionDescriptions/Convert2streamapi.html b/resources-en/src/inspectionDescriptions/Convert2streamapi.html index ff190f897875..3e2b1d886ea2 100644 --- a/resources-en/src/inspectionDescriptions/Convert2streamapi.html +++ b/resources-en/src/inspectionDescriptions/Convert2streamapi.html @@ -1,6 +1,6 @@ -This inspection reports foreach loops which can be replaced with stream API calls. +This inspection reports loops which can be replaced with stream API calls.

Stream API is not available under Java 1.7 or earlier JVMs. diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 8193fde74466..005b554bb44e 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -760,7 +760,7 @@ -