Merge remote-tracking branch 'origin/master' into amakeev/cmake-configs-master

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

Some files were not shown because too many files have changed in this diff Show More