diff --git a/build/groovy/org/jetbrains/intellij/build/BuildTasks.groovy b/build/groovy/org/jetbrains/intellij/build/BuildTasks.groovy index 2f5bf5c79eff..dc56e6436be0 100644 --- a/build/groovy/org/jetbrains/intellij/build/BuildTasks.groovy +++ b/build/groovy/org/jetbrains/intellij/build/BuildTasks.groovy @@ -38,33 +38,11 @@ abstract class BuildTasks { */ abstract void zipSourcesOfModules(Collection modules, String targetFilePath) - /** - * Updates search/searchableOptions.xml file in {@code targetModuleName} module output directory - *
- * todo[nik] this is temporary solution until code from layouts.gant files moved to the new builders. After that this method will - * be called inside {@link #buildDistributions()} - */ - abstract void buildSearchableOptions(String targetModuleName, List modulesToIndex, List pathsToLicenses) - - /** - * Creates a copy of *ApplicationInfo.xml file with substituted __BUILD_NUMBER__ and __BUILD_DATE__ placeholders - *
- * todo[nik] this is temporary solution until code from layouts.gant files moved to the new builders. After that this method will - * be called inside {@link #buildDistributions()} - * @return path to the copied file - */ - abstract File patchApplicationInfo() - - /** - * Creates distribution for all operating systems from JAR files located at {@link BuildPaths#distAll} - */ - abstract void buildDistributions() - /** * Produces distributions for all operating systems from sources. This includes compiling required modules, packing their output into JAR * files accordingly to {@link ProductProperties#productLayout}, and creating distributions and installers for all OS. */ - abstract void compileModulesAndBuildDistributions() + abstract void buildDistributions() abstract void compileProjectAndTests(List includingTestsInModules) @@ -97,6 +75,6 @@ abstract class BuildTasks { ProductProperties productProperties = (ProductProperties) Class.forName(productPropertiesClassName).constructors[0].newInstance(projectHome) def context = BuildContext.createContext(binding.ant, binding.projectBuilder, binding.project, binding.global, "$projectHome/$communityHomeRelativePath", projectHome, productProperties, proprietaryBuildTools) - create(context).compileModulesAndBuildDistributions() + create(context).buildDistributions() } } \ No newline at end of file diff --git a/build/groovy/org/jetbrains/intellij/build/IdeaCommunityBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/IdeaCommunityBuilder.groovy index 3e4038b752e7..c08dceb9ac7e 100644 --- a/build/groovy/org/jetbrains/intellij/build/IdeaCommunityBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/IdeaCommunityBuilder.groovy @@ -41,13 +41,13 @@ class IdeaCommunityBuilder { } void buildDistJars() { - BuildTasks.create(buildContext).compileModulesAndBuildDistributions() + BuildTasks.create(buildContext).buildDistributions() layoutAdditionalArtifacts() } void buildDistributions() { def tasks = BuildTasks.create(buildContext) - tasks.compileModulesAndBuildDistributions() + tasks.buildDistributions() layoutAdditionalArtifacts(true) tasks.buildUpdaterJar() } diff --git a/build/groovy/org/jetbrains/intellij/build/ProductProperties.groovy b/build/groovy/org/jetbrains/intellij/build/ProductProperties.groovy index 78d246f8b6b0..a31b68493867 100644 --- a/build/groovy/org/jetbrains/intellij/build/ProductProperties.groovy +++ b/build/groovy/org/jetbrains/intellij/build/ProductProperties.groovy @@ -164,8 +164,6 @@ abstract class ProductProperties { */ boolean enableYourkitAgentInEAP = false - List excludedPlugins = [] - /** * Specified additional modules (not included into the product layout) which need to be compiled when product is built. * todo[nik] get rid of this diff --git a/build/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy b/build/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy index 6238cc0a438c..369ea2a80951 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy @@ -311,9 +311,7 @@ class BuildContextImpl extends BuildContext { private boolean isJavaSupportedInProduct() { def productLayout = productProperties.productLayout - return productLayout.mainJarName == null || - //todo[nik] remove this condition later; currently build scripts for IDEA don't fully migrated to the new scheme - productLayout.includedPlatformModules.contains("execution-impl") + return productLayout.includedPlatformModules.contains("execution-impl") } @CompileDynamic diff --git a/build/groovy/org/jetbrains/intellij/build/impl/BuildTasksImpl.groovy b/build/groovy/org/jetbrains/intellij/build/impl/BuildTasksImpl.groovy index 9d5fcfb40b60..31c0f15ec0e3 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/BuildTasksImpl.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/BuildTasksImpl.groovy @@ -91,12 +91,6 @@ class BuildTasksImpl extends BuildTasks { } } - @Override - void buildSearchableOptions(String targetModuleName, List modulesToIndex, List pathsToLicenses) { - buildSearchableOptions(new File(buildContext.projectBuilder.moduleOutput(buildContext.findRequiredModule(targetModuleName))), modulesToIndex, pathsToLicenses) - } - -//todo[nik] do we need 'cp' and 'jvmArgs' parameters? void buildSearchableOptions(File targetDirectory, List modulesToIndex, List pathsToLicenses) { buildContext.executeStep("Build searchable options index", BuildOptions.SEARCHABLE_OPTIONS_INDEX_STEP, { def javaRuntimeClasses = "${buildContext.projectBuilder.moduleOutput(buildContext.findModule("java-runtime"))}" @@ -187,7 +181,6 @@ idea.fatal.error.notification=disabled return propertiesFile } - @Override File patchApplicationInfo() { def sourceFile = buildContext.findApplicationInfoInSources() def targetFile = new File(buildContext.paths.temp, sourceFile.name) @@ -229,38 +222,6 @@ idea.fatal.error.notification=disabled src.filterLine { String it -> !it.contains('appender-ref ref="CONSOLE-WARN"') }.writeTo(dst.newWriter()).close() } - @Override - void buildDistributions() { - layoutShared() - - def propertiesFile = patchIdeaPropertiesFile() - List> tasks = [ - createDistributionForOsTask("win", { BuildContext context -> - context.windowsDistributionCustomizer?.with {new WindowsDistributionBuilder(context, it, propertiesFile)} - }), - createDistributionForOsTask("linux", { BuildContext context -> - context.linuxDistributionCustomizer?.with {new LinuxDistributionBuilder(context, it, propertiesFile)} - }), - createDistributionForOsTask("mac", { BuildContext context -> - context.macDistributionCustomizer?.with {new MacDistributionBuilder(context, it, propertiesFile)} - }) - ] - - List paths = runInParallel(tasks).findAll {it != null} - - if (buildContext.productProperties.buildCrossPlatformDistribution) { - if (paths.size() == 3) { - buildContext.executeStep("Build cross-platform distribution", BuildOptions.CROSS_PLATFORM_DISTRIBUTION_STEP) { - def crossPlatformBuilder = new CrossPlatformDistributionBuilder(buildContext) - crossPlatformBuilder.buildCrossPlatformZip(paths[0], paths[1], paths[2]) - } - } - else { - buildContext.messages.info("Skipping building cross-platform distribution because some OS-specific distributions were skipped") - } - } - } - private static BuildTaskRunnable createDistributionForOsTask(String taskName, Function factory) { new BuildTaskRunnable(taskName) { @Override @@ -279,9 +240,11 @@ idea.fatal.error.notification=disabled } @Override - void compileModulesAndBuildDistributions() { + void buildDistributions() { checkProductProperties() - def distributionJARsBuilder = new DistributionJARsBuilder(buildContext) + + def patchedApplicationInfo = patchApplicationInfo() + def distributionJARsBuilder = new DistributionJARsBuilder(buildContext, patchedApplicationInfo) compileModules(buildContext.productProperties.productLayout.includedPluginModules + distributionJARsBuilder.platformModules + buildContext.productProperties.additionalModulesToCompile, buildContext.productProperties.modulesToCompileTests) buildContext.messages.block("Build platform and plugin JARs") { @@ -289,24 +252,56 @@ idea.fatal.error.notification=disabled distributionJARsBuilder.buildAdditionalArtifacts() } if (buildContext.productProperties.scrambleMainJar) { - if (buildContext.proprietaryBuildTools.scrambleTool != null) { - buildContext.proprietaryBuildTools.scrambleTool.scramble(buildContext.productProperties.productLayout.mainJarName, buildContext) + scramble() + } + + layoutShared() + + def propertiesFile = patchIdeaPropertiesFile() + List> tasks = [ + createDistributionForOsTask("win", { BuildContext context -> + context.windowsDistributionCustomizer?.with { new WindowsDistributionBuilder(context, it, propertiesFile, patchedApplicationInfo) } + }), + createDistributionForOsTask("linux", { BuildContext context -> + context.linuxDistributionCustomizer?.with { new LinuxDistributionBuilder(context, it, propertiesFile) } + }), + createDistributionForOsTask("mac", { BuildContext context -> + context.macDistributionCustomizer?.with { new MacDistributionBuilder(context, it, propertiesFile) } + }) + ] + + List paths = runInParallel(tasks).findAll { it != null } + + if (buildContext.productProperties.buildCrossPlatformDistribution) { + if (paths.size() == 3) { + buildContext.executeStep("Build cross-platform distribution", BuildOptions.CROSS_PLATFORM_DISTRIBUTION_STEP) { + def crossPlatformBuilder = new CrossPlatformDistributionBuilder(buildContext) + crossPlatformBuilder.buildCrossPlatformZip(paths[0], paths[1], paths[2]) + } } else { - buildContext.messages.warning("Scrambling skipped: 'scrambleTool' isn't defined") + buildContext.messages.info("Skipping building cross-platform distribution because some OS-specific distributions were skipped") } - buildContext.ant.zip(destfile: "$buildContext.paths.artifacts/internalUtilities.zip") { - fileset(file: "$buildContext.paths.buildOutputRoot/internal/internalUtilities.jar") - fileset(dir: "$buildContext.paths.communityHome/lib") { - include(name: "junit-4*.jar") - include(name: "hamcrest-core-*.jar") - } - zipfileset(src: "$buildContext.paths.buildOutputRoot/internal/internalUtilities.jar") { - include(name: "*.xml") - } + } + } + + private void scramble() { + if (buildContext.proprietaryBuildTools.scrambleTool != null) { + buildContext.proprietaryBuildTools.scrambleTool.scramble(buildContext.productProperties.productLayout.mainJarName, buildContext) + } + else { + buildContext.messages.warning("Scrambling skipped: 'scrambleTool' isn't defined") + } + buildContext.ant.zip(destfile: "$buildContext.paths.artifacts/internalUtilities.zip") { + fileset(file: "$buildContext.paths.buildOutputRoot/internal/internalUtilities.jar") + fileset(dir: "$buildContext.paths.communityHome/lib") { + include(name: "junit-4*.jar") + include(name: "hamcrest-core-*.jar") + } + zipfileset(src: "$buildContext.paths.buildOutputRoot/internal/internalUtilities.jar") { + include(name: "*.xml") } } - buildDistributions() } private void checkProductProperties() { @@ -478,7 +473,7 @@ idea.fatal.error.notification=disabled @Override void buildUnpackedDistribution(String targetDirectory) { - def jarsBuilder = new DistributionJARsBuilder(buildContext) + def jarsBuilder = new DistributionJARsBuilder(buildContext, patchApplicationInfo()) jarsBuilder.buildJARs() layoutShared() diff --git a/build/groovy/org/jetbrains/intellij/build/impl/CrossPlatformDistributionBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/CrossPlatformDistributionBuilder.groovy index 88a408519817..ba9494402aa4 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/CrossPlatformDistributionBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/CrossPlatformDistributionBuilder.groovy @@ -59,7 +59,6 @@ class CrossPlatformDistributionBuilder { buildContext.ant.zip(zipfile: targetPath, duplicate: "fail") { fileset(dir: buildContext.paths.distAll) { exclude(name: "bin/idea.properties") - exclude(name: "lib/libpty/**") //todo[nik] this is temporary workaround until IDEA fully migrates to the new scheme } fileset(dir: zipDir) diff --git a/build/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy index 6175bb62da95..212a9f4541ea 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy @@ -39,8 +39,10 @@ class DistributionJARsBuilder { private final BuildContext buildContext private final Set usedModules = new LinkedHashSet<>() private final PlatformLayout platform + private final File patchedApplicationInfo - DistributionJARsBuilder(BuildContext buildContext) { + DistributionJARsBuilder(BuildContext buildContext, File patchedApplicationInfo) { + this.patchedApplicationInfo = patchedApplicationInfo this.buildContext = buildContext buildContext.ant.patternset(id: RESOURCES_INCLUDED) { include(name: "**/*Bundle*.properties") @@ -205,7 +207,7 @@ class DistributionJARsBuilder { layoutBuilder.patchModuleOutput(productLayout.searchableOptionsModule, FileUtil.toSystemIndependentName(searchableOptionsDir.absolutePath)) } - def applicationInfoFile = FileUtil.toSystemIndependentName(buildTasks.patchApplicationInfo().absolutePath) + def applicationInfoFile = FileUtil.toSystemIndependentName(patchedApplicationInfo.absolutePath) def applicationInfoDir = "$buildContext.paths.temp/applicationInfo" ant.copy(file: applicationInfoFile, todir: "$applicationInfoDir/idea") layoutBuilder.patchModuleOutput(buildContext.productProperties.applicationInfoModule, applicationInfoDir) diff --git a/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy index d2e245facb84..efc5f29bd160 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy @@ -28,9 +28,11 @@ import org.jetbrains.jps.model.module.JpsModuleSourceRoot class WindowsDistributionBuilder extends OsSpecificDistributionBuilder { private final WindowsDistributionCustomizer customizer private final File ideaProperties + private final File patchedApplicationInfo - WindowsDistributionBuilder(BuildContext buildContext, WindowsDistributionCustomizer customizer, File ideaProperties) { + WindowsDistributionBuilder(BuildContext buildContext, WindowsDistributionCustomizer customizer, File ideaProperties, File patchedApplicationInfo) { super(BuildOptions.OS_WINDOWS, "Windows", buildContext) + this.patchedApplicationInfo = patchedApplicationInfo this.customizer = customizer this.ideaProperties = ideaProperties } @@ -101,7 +103,6 @@ class WindowsDistributionBuilder extends OsSpecificDistributionBuilder { private void generateScripts(String winDistPath) { String fullName = buildContext.applicationInfo.productName - //todo[nik] looks like names without .exe were also supported, do we need this? String vmOptionsFileName = "${buildContext.productProperties.baseFileName}%BITS%.exe" String classPath = "SET CLASS_PATH=%IDE_HOME%\\lib\\${buildContext.bootClassPathJarNames[0]}\n" @@ -185,7 +186,7 @@ IDS_VM_OPTIONS=$vmOptions buildContext.ant.java(classname: "com.pme.launcher.LauncherGeneratorMain", fork: "true", failonerror: "true") { sysproperty(key: "java.awt.headless", value: "true") arg(value: inputPath) - arg(value: buildContext.findApplicationInfoInSources().absolutePath) + arg(value: patchedApplicationInfo.absolutePath) arg(value: "$communityHome/native/WinLauncher/WinLauncher/resource.h") arg(value: launcherPropertiesPath) arg(value: outputPath) diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index c1a30023bf3a..2315313db58a 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -16,6 +16,7 @@ import org.jetbrains.intellij.build.* +import org.jetbrains.intellij.build.impl.BuildTasksImpl import org.jetbrains.jps.util.JpsPathUtil import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome @@ -41,7 +42,7 @@ boolean setPluginAndIDEVersionInPluginXml() { } List getExcludedPlugins() { - return isDefined("productProperties") ? productProperties.excludedPlugins : [] + return [] } /** @@ -51,7 +52,7 @@ def layoutFull(BuildContext context) { binding.setVariable("productProperties", context.productProperties) String home = context.paths.communityHome String targetDirectory = context.paths.distAll - File patchedApplicationInfo = BuildTasks.create(context).patchApplicationInfo() + File patchedApplicationInfo = ((BuildTasksImpl)BuildTasks.create(context)).patchApplicationInfo() projectBuilder.stage("layout to $targetDirectory") List jpsCommonModules = ["jps-model-impl", "jps-model-serialization"] diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java index 3c8cc9e04919..0379bfaa2990 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java @@ -195,9 +195,10 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection return canBeConvertedToLambda(aClass, acceptParameterizedFunctionTypes, true, ignoredRuntimeAnnotations); } - public static boolean isClassAndMethodSuitableForConversion(PsiAnonymousClass aClass, - PsiMethod method, - Set ignoredRuntimeAnnotations) { + public static boolean isLambdaForm(PsiAnonymousClass aClass, Set ignoredRuntimeAnnotations) { + PsiMethod[] methods = aClass.getMethods(); + if(methods.length != 1) return false; + PsiMethod method = methods[0]; return aClass.getFields().length == 0 && aClass.getInnerClasses().length == 0 && aClass.getInitializers().length == 0 && @@ -222,16 +223,9 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection } final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); if (interfaceMethod != null && (acceptParameterizedFunctionTypes || !interfaceMethod.hasTypeParameters())) { - final PsiMethod[] methods = aClass.getMethods(); - if (methods.length == 1) { - final PsiMethod method = methods[0]; - if (isClassAndMethodSuitableForConversion(aClass, method, ignoredRuntimeAnnotations)) { - final PsiType inferredType = getInferredType(aClass, method); - if (inferredType == null) { - return false; - } - return true; - } + if (isLambdaForm(aClass, ignoredRuntimeAnnotations)) { + final PsiMethod method = aClass.getMethods()[0]; + return getInferredType(aClass, method) != null; } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousHasLambdaAlternativeInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousHasLambdaAlternativeInspection.java index b259c5dc956d..ef5ad5741e6f 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousHasLambdaAlternativeInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousHasLambdaAlternativeInspection.java @@ -66,21 +66,19 @@ public class AnonymousHasLambdaAlternativeInspection extends BaseJavaBatchLocalI @Override public void visitAnonymousClass(final PsiAnonymousClass aClass) { super.visitAnonymousClass(aClass); - PsiMethod[] methods = aClass.getMethods(); - if(methods.length == 1) { - PsiMethod method = methods[0]; - PsiExpressionList argumentList = aClass.getArgumentList(); - if (AnonymousCanBeLambdaInspection.isClassAndMethodSuitableForConversion(aClass, method, Collections.emptySet()) && - argumentList != null && argumentList.getExpressions().length == 0) { - PsiClassType type = aClass.getBaseClassType(); - AnonymousLambdaAlternative alternative = getAlternative(type.resolve(), method); - if(alternative != null) { - final PsiElement lBrace = aClass.getLBrace(); - LOG.assertTrue(lBrace != null); - final TextRange rangeInElement = new TextRange(0, lBrace.getStartOffsetInParent() + aClass.getStartOffsetInParent() - 1); - holder.registerProblem(aClass.getParent(), "Anonymous #ref #loc can be replaced with "+alternative.myReplacementMessage, - ProblemHighlightType.LIKE_UNUSED_SYMBOL, rangeInElement, new ReplaceWithLambdaAlternativeFix(alternative)); - } + PsiExpressionList argumentList = aClass.getArgumentList(); + if (AnonymousCanBeLambdaInspection.isLambdaForm(aClass, Collections.emptySet()) && + argumentList != null && + argumentList.getExpressions().length == 0) { + PsiMethod method = aClass.getMethods()[0]; + PsiClassType type = aClass.getBaseClassType(); + AnonymousLambdaAlternative alternative = getAlternative(type.resolve(), method); + if(alternative != null) { + final PsiElement lBrace = aClass.getLBrace(); + LOG.assertTrue(lBrace != null); + final TextRange rangeInElement = new TextRange(0, lBrace.getStartOffsetInParent() + aClass.getStartOffsetInParent() - 1); + holder.registerProblem(aClass.getParent(), "Anonymous #ref #loc can be replaced with "+alternative.myReplacementMessage, + ProblemHighlightType.LIKE_UNUSED_SYMBOL, rangeInElement, new ReplaceWithLambdaAlternativeFix(alternative)); } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullParameterConstraintChecker.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullParameterConstraintChecker.java index 218656cfb91d..39ba4a0e1475 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullParameterConstraintChecker.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullParameterConstraintChecker.java @@ -18,6 +18,7 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.codeInspection.dataFlow.instructions.AssignInstruction; import com.intellij.codeInspection.dataFlow.instructions.Instruction; +import com.intellij.codeInspection.dataFlow.instructions.PushInstruction; import com.intellij.codeInspection.dataFlow.instructions.ReturnInstruction; import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; @@ -47,10 +48,12 @@ import java.util.Set; */ class NullParameterConstraintChecker extends DataFlowRunner { private final Set myPossiblyViolatedParameters; + private final Set myUsedParameters; private NullParameterConstraintChecker(Collection parameters, boolean isOnTheFly) { super(false, true, isOnTheFly); myPossiblyViolatedParameters = new THashSet<>(parameters); + myUsedParameters = new THashSet<>(); } @NotNull @@ -73,7 +76,7 @@ class NullParameterConstraintChecker extends DataFlowRunner { final NullParameterConstraintChecker checker = new NullParameterConstraintChecker(nullableParameters, true); checker.analyzeMethod(method.getBody(), new StandardInstructionVisitor()); - return checker.myPossiblyViolatedParameters.toArray(new PsiParameter[checker.myPossiblyViolatedParameters.size()]); + return checker.myPossiblyViolatedParameters.stream().filter(checker.myUsedParameters::contains).toArray(PsiParameter[]::new); } @NotNull @@ -81,6 +84,16 @@ class NullParameterConstraintChecker extends DataFlowRunner { protected DfaInstructionState[] acceptInstruction(@NotNull InstructionVisitor visitor, @NotNull DfaInstructionState instructionState) { Instruction instruction = instructionState.getInstruction(); + if (instruction instanceof PushInstruction) { + final DfaValue var = ((PushInstruction)instruction).getValue(); + if (var instanceof DfaVariableValue) { + final PsiModifierListOwner psiVar = ((DfaVariableValue)var).getPsiVariable(); + if (psiVar instanceof PsiParameter) { + myUsedParameters.add((PsiParameter)psiVar); + } + } + } + if (instruction instanceof AssignInstruction) { final DfaValue value = ((AssignInstruction)instruction).getAssignedValue(); if (value instanceof DfaVariableValue) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StringExpressionHelper.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StringExpressionHelper.java index c9f5d4505709..a19e953e6437 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StringExpressionHelper.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StringExpressionHelper.java @@ -110,7 +110,7 @@ public class StringExpressionHelper { Collection elements = DfaUtil.getPossibleInitializationElements(expression); for (PsiElement element : elements) { - Pair expr = evaluateExpression(element); + Pair expr = evaluateExpression(element, visited); if (expr != null) return expr; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/java18api/Java8CollectionsApiInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/java18api/Java8CollectionsApiInspection.java index 4a9a02fe601b..55008d12b530 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/java18api/Java8CollectionsApiInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/java18api/Java8CollectionsApiInspection.java @@ -239,14 +239,14 @@ public class Java8CollectionsApiInspection extends BaseJavaBatchLocalInspectionT (getArgument == null || EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(getArgument, putKeyArgument))) { LocalQuickFix fix = null; if (ExpressionUtils.isSimpleExpression(putValueArgument)) { - fix = new ReplaceWithMapPutIfAbsentFix(putMethodCall, "putIfAbsent"); + fix = new ReplaceConditionalMapPutFix(putMethodCall, false); } else if ((maybePutMethodCall.getParent() instanceof PsiExpressionStatement) && // only if result of put is not used LambdaGenerationUtil.canBeUncheckedLambda(putValueArgument)) { - fix = new ReplaceWithMapPutIfAbsentFix(putMethodCall, "computeIfAbsent"); + fix = new ReplaceConditionalMapPutFix(putMethodCall, true); } else if (mySuggestPutIfAbsentForComplexExpression) { - fix = new ReplaceWithMapPutIfAbsentFix(putMethodCall, "putIfAbsent"); + fix = new ReplaceConditionalMapPutFix(putMethodCall, false); } if(fix != null) { holder.registerProblem(context, QuickFixBundle.message("java.8.collections.api.inspection.description"), fix); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/java18api/ReplaceWithMapPutIfAbsentFix.java b/java/java-analysis-impl/src/com/intellij/codeInspection/java18api/ReplaceConditionalMapPutFix.java similarity index 92% rename from java/java-analysis-impl/src/com/intellij/codeInspection/java18api/ReplaceWithMapPutIfAbsentFix.java rename to java/java-analysis-impl/src/com/intellij/codeInspection/java18api/ReplaceConditionalMapPutFix.java index 2d74c1f5aa7a..693906636de1 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/java18api/ReplaceWithMapPutIfAbsentFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/java18api/ReplaceConditionalMapPutFix.java @@ -32,14 +32,17 @@ import org.jetbrains.annotations.NotNull; /** * @author Dmitry Batkovich */ -public class ReplaceWithMapPutIfAbsentFix implements LocalQuickFix { +public class ReplaceConditionalMapPutFix implements LocalQuickFix { + private static final String COMPUTE_IF_ABSENT_METHOD = "computeIfAbsent"; + private static final String PUT_IF_ABSENT_METHOD = "putIfAbsent"; + private final SmartPsiElementPointer myPutExpressionPointer; private final String myMethodName; - public ReplaceWithMapPutIfAbsentFix(PsiMethodCallExpression putExpression, String methodName) { + public ReplaceConditionalMapPutFix(PsiMethodCallExpression putExpression, boolean useComputeIfAbsent) { final SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(putExpression.getProject()); myPutExpressionPointer = smartPointerManager.createSmartPsiElementPointer(putExpression); - myMethodName = methodName; // either "putIfAbsent" or "computeIfAbsent" + myMethodName = useComputeIfAbsent ? COMPUTE_IF_ABSENT_METHOD : PUT_IF_ABSENT_METHOD; } @Override @@ -74,7 +77,7 @@ public class ReplaceWithMapPutIfAbsentFix implements LocalQuickFix { final Couple boundText = getBoundText(putContainingElement, putExpression); String valueArgument = putExpression.getArgumentList().getExpressions()[1].getText(); - if(myMethodName.equals("computeIfAbsent")) { + if(myMethodName.equals(COMPUTE_IF_ABSENT_METHOD)) { String varName = JavaCodeStyleManager.getInstance(project).suggestUniqueVariableName("k", putExpression, true); valueArgument = varName + " -> " + valueArgument; } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/InlineStreamMapAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/InlineStreamMapAction.java new file mode 100644 index 000000000000..7dbb7f3a3fce --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/InlineStreamMapAction.java @@ -0,0 +1,300 @@ +/* + * 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.codeInsight.intention.impl; + +import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.codeInsight.FileModificationService; +import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.util.LambdaRefactoringUtil; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.style.MethodRefCanBeReplacedWithLambdaInspection; +import one.util.streamex.StreamEx; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +public class InlineStreamMapAction extends PsiElementBaseIntentionAction { + private static final Logger LOG = Logger.getInstance(InlineStreamMapAction.class.getName()); + + private static final Set MAP_METHODS = + StreamEx.of("map", "mapToInt", "mapToLong", "mapToDouble", "mapToObj", "boxed", "asLongStream", "asDoubleStream").toSet(); + + private static final Set NEXT_METHODS = StreamEx + .of("flatMap", "flatMapToInt", "flatMapToLong", "flatMapToDouble", "forEach", "forEachOrdered", "anyMatch", "noneMatch", "allMatch") + .append(MAP_METHODS).toSet(); + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull final PsiElement element) { + if (!(element instanceof PsiIdentifier)) return false; + final PsiElement parent = element.getParent(); + if (!(parent instanceof PsiReferenceExpression)) return false; + final PsiElement gParent = parent.getParent(); + if (!(gParent instanceof PsiMethodCallExpression)) return false; + PsiMethodCallExpression curCall = (PsiMethodCallExpression)gParent; + if (!isMapCall(curCall)) return false; + PsiMethodCallExpression nextCall = getNextExpressionToMerge(curCall); + if(nextCall == null) return false; + String key = curCall.getArgumentList().getExpressions().length == 0 || nextCall.getArgumentList().getExpressions().length == 0 ? + "intention.inline.map.merge.text" : "intention.inline.map.inline.text"; + setText(CodeInsightBundle.message(key, element.getText(), nextCall.getMethodExpression().getReferenceName())); + return true; + } + + private static boolean isMapCall(@NotNull PsiMethodCallExpression methodCallExpression) { + String name = methodCallExpression.getMethodExpression().getReferenceName(); + if (name == null || !MAP_METHODS.contains(name)) return false; + + final PsiExpressionList argumentList = methodCallExpression.getArgumentList(); + final PsiExpression[] expressions = argumentList.getExpressions(); + if (!name.startsWith("map") && expressions.length == 0) return true; + if (expressions.length != 1) return false; + if (!isSupportedForConversion(expressions[0], true)) return false; + + final PsiMethod method = methodCallExpression.resolveMethod(); + if (method == null) return false; + final PsiClass containingClass = method.getContainingClass(); + return InheritanceUtil.isInheritor(containingClass, CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM); + } + + private static boolean isSupportedForConversion(PsiExpression expression, boolean requireExpressionLambda) { + if(expression instanceof PsiLambdaExpression) { + PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)expression; + return lambdaExpression.getParameterList().getParametersCount() == 1 && + (!requireExpressionLambda || LambdaUtil.extractSingleExpressionFromBody(lambdaExpression.getBody()) != null); + } else if(expression instanceof PsiMethodReferenceExpression) { + PsiMethodReferenceExpression methodReference = (PsiMethodReferenceExpression)expression; + return !MethodRefCanBeReplacedWithLambdaInspection.isWithSideEffects(methodReference); + } + return false; + } + + @Nullable + private static PsiMethodCallExpression getNextExpressionToMerge(PsiMethodCallExpression methodCallExpression) { + PsiElement parent = methodCallExpression.getParent(); + if(!(parent instanceof PsiReferenceExpression)) return null; + PsiElement gParent = parent.getParent(); + if(!(gParent instanceof PsiMethodCallExpression)) return null; + String nextName = ((PsiReferenceExpression)parent).getReferenceName(); + PsiMethodCallExpression nextCall = (PsiMethodCallExpression)gParent; + if(nextName == null || !NEXT_METHODS.contains(nextName) || translateName(methodCallExpression, nextCall) == null) return null; + PsiExpressionList argumentList = (nextCall).getArgumentList(); + PsiExpression[] expressions = argumentList.getExpressions(); + if(expressions.length == 0) { + if (!nextName.equals("boxed") && !nextName.equals("asLongStream") && !nextName.equals("asDoubleStream")) return null; + return nextCall; + } + if (expressions.length != 1 || !isSupportedForConversion(expressions[0], false)) return null; + + return nextCall; + } + + /** + * Generate name of joint method call which combines two given calls + * + * @param prevCall previous call (assumed to be in MAP_METHODS) + * @param nextCall next call (assumed to be in NEXT_METHODS) + * @return a name of the resulting method + */ + @Nullable + private static String translateName(@NotNull PsiMethodCallExpression prevCall, @NotNull PsiMethodCallExpression nextCall) { + PsiMethod nextMethod = nextCall.resolveMethod(); + if (nextMethod == null) return null; + String nextName = nextMethod.getName(); + PsiMethod method = prevCall.resolveMethod(); + if (method == null) return null; + PsiClass prevClass = method.getContainingClass(); + if (prevClass == null) return null; + String prevClassName = prevClass.getQualifiedName(); + if (prevClassName == null) return null; + String prevName = method.getName(); + if (nextName.endsWith("Match") || nextName.startsWith("forEach")) return nextName; + if (nextName.equals("map")) { + return translateMap(prevName); + } + if (prevName.equals("map")) { + return translateMap(nextName); + } + if(MAP_METHODS.contains(nextName)) { + PsiType type = nextMethod.getReturnType(); + if(!(type instanceof PsiClassType)) return null; + PsiClass nextClass = ((PsiClassType)type).resolve(); + if(nextClass == null) return null; + String nextClassName = nextClass.getQualifiedName(); + if(nextClassName == null) return null; + if(prevClassName.equals(nextClassName)) return "map"; + switch(nextClassName) { + case CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM: + return "mapToInt"; + case CommonClassNames.JAVA_UTIL_STREAM_LONG_STREAM: + return "mapToLong"; + case CommonClassNames.JAVA_UTIL_STREAM_DOUBLE_STREAM: + return "mapToDouble"; + case CommonClassNames.JAVA_UTIL_STREAM_STREAM: + return "mapToObj"; + default: + return null; + } + } + if(nextName.equals("flatMap") && prevClassName.equals(CommonClassNames.JAVA_UTIL_STREAM_STREAM)) { + String mapMethod = translateMap(prevName); + return "flatM"+mapMethod.substring(1); + } + return null; + } + + @NotNull + private static String translateMap(String nextMethod) { + switch (nextMethod) { + case "boxed": + return "mapToObj"; + case "asLongStream": + return "mapToLong"; + case "asDoubleStream": + return "mapToDouble"; + default: + return nextMethod; + } + } + + @Override + @NotNull + public String getFamilyName() { + return CodeInsightBundle.message("intention.inline.map.family"); + } + + @Override + public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { + PsiMethodCallExpression mapCall = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class); + if(mapCall == null) return; + + PsiMethodCallExpression nextCall = getNextExpressionToMerge(mapCall); + if(nextCall == null) return; + + PsiExpression nextQualifier = nextCall.getMethodExpression().getQualifierExpression(); + if(nextQualifier == null) return; + + String newName = translateName(mapCall, nextCall); + if(newName == null) return; + + if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return; + + PsiLambdaExpression previousLambda = getLambda(mapCall); + + LOG.assertTrue(previousLambda != null); + PsiExpression previousBody = LambdaUtil.extractSingleExpressionFromBody(previousLambda.getBody()); + LOG.assertTrue(previousBody != null); + + PsiLambdaExpression lambda = getLambda(nextCall); + LOG.assertTrue(lambda != null); + + if(!lambda.isPhysical()) { + lambda = (PsiLambdaExpression)nextCall.getArgumentList().add(lambda); + } + PsiElement body = lambda.getBody(); + LOG.assertTrue(body != null); + + PsiParameter[] nextParameters = lambda.getParameterList().getParameters(); + LOG.assertTrue(nextParameters.length == 1); + PsiParameter[] prevParameters = previousLambda.getParameterList().getParameters(); + LOG.assertTrue(prevParameters.length == 1); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + for(PsiReference ref : ReferencesSearch.search(nextParameters[0], new LocalSearchScope(body)).findAll()) { + PsiElement e = ref.getElement(); + PsiExpression replacement = previousBody; + if (e.getParent() instanceof PsiExpression && + ParenthesesUtils.areParenthesesNeeded(previousBody, (PsiExpression)e.getParent(), false)) { + replacement = factory.createExpressionFromText("(a)", e); + PsiExpression parenthesized = ((PsiParenthesizedExpression)replacement).getExpression(); + LOG.assertTrue(parenthesized != null); + parenthesized.replace(previousBody); + } + e.replace(replacement); + } + nextParameters[0].replace(prevParameters[0]); + PsiElement nameElement = nextCall.getMethodExpression().getReferenceNameElement(); + if(nameElement != null && !nameElement.getText().equals(newName)) { + nameElement.replace(factory.createIdentifier(newName)); + } + PsiExpression prevQualifier = mapCall.getMethodExpression().getQualifierExpression(); + if(prevQualifier == null) { + nextQualifier.delete(); + } else { + nextQualifier.replace(prevQualifier); + } + CodeStyleManager.getInstance(project).reformat(lambda); + } + + @Nullable + private static PsiLambdaExpression getLambda(PsiMethodCallExpression call) { + PsiExpression[] expressions = call.getArgumentList().getExpressions(); + if(expressions.length == 1) { + PsiExpression expression = expressions[0]; + if(expression instanceof PsiLambdaExpression) return (PsiLambdaExpression)expression; + if(expression instanceof PsiMethodReferenceExpression) { + return LambdaRefactoringUtil.convertMethodReferenceToLambda((PsiMethodReferenceExpression)expression, false, true); + } + return null; + } + if(expressions.length != 0) return null; + PsiMethod method = call.resolveMethod(); + if(method == null) return null; + PsiClass containingClass = method.getContainingClass(); + if(containingClass == null) return null; + String className = containingClass.getQualifiedName(); + if(className == null) return null; + String varName; + String type; + switch (className) { + case CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM: + varName = "i"; + type = CommonClassNames.JAVA_LANG_INTEGER; + break; + case CommonClassNames.JAVA_UTIL_STREAM_LONG_STREAM: + varName = "l"; + type = CommonClassNames.JAVA_LANG_LONG; + break; + case CommonClassNames.JAVA_UTIL_STREAM_DOUBLE_STREAM: + varName = "d"; + type = CommonClassNames.JAVA_LANG_DOUBLE; + break; + default: + return null; + } + varName = JavaCodeStyleManager.getInstance(call.getProject()).suggestUniqueVariableName(varName, call, true); + String expression; + if("boxed".equals(method.getName())) { + expression = varName+" -> ("+type+")"+varName; + } else if("asLongStream".equals(method.getName())) { + expression = varName+" -> (long)"+varName; + } else if("asDoubleStream".equals(method.getName())) { + expression = varName+" -> (double)"+varName; + } else return null; + PsiElementFactory factory = JavaPsiFacade.getElementFactory(call.getProject()); + return (PsiLambdaExpression)factory.createExpressionFromText(expression, call); + } +} diff --git a/java/java-impl/src/com/intellij/ide/actions/JavaQualifiedNameProvider.java b/java/java-impl/src/com/intellij/ide/actions/JavaQualifiedNameProvider.java index 67c09e9cf4c1..d0e9d102cbd1 100644 --- a/java/java-impl/src/com/intellij/ide/actions/JavaQualifiedNameProvider.java +++ b/java/java-impl/src/com/intellij/ide/actions/JavaQualifiedNameProvider.java @@ -219,30 +219,27 @@ public class JavaQualifiedNameProvider implements QualifiedNameProvider { final PsiExpression expression; try { expression = factory.createExpressionFromText(toInsert + suffix, elementAtCaret); - } - catch (IncorrectOperationException e) { - LOG.error(e); - return; - } - final PsiReferenceExpression referenceExpression = expression instanceof PsiMethodCallExpression - ? ((PsiMethodCallExpression)expression).getMethodExpression() - : expression instanceof PsiReferenceExpression - ? (PsiReferenceExpression)expression - : null; - if (referenceExpression == null || !referenceExpression.isValid()) { - toInsert = fqn; - } - else if (!isReferencedTo(referenceExpression, targetElement)) { - try { - referenceExpression.bindToElement(targetElement); - } - catch (IncorrectOperationException e) { - // failed to bind - } - if (!referenceExpression.isValid() || !isReferencedTo(referenceExpression, targetElement)) { + final PsiReferenceExpression referenceExpression = expression instanceof PsiMethodCallExpression + ? ((PsiMethodCallExpression)expression).getMethodExpression() + : expression instanceof PsiReferenceExpression + ? (PsiReferenceExpression)expression + : null; + if (referenceExpression == null || !referenceExpression.isValid()) { toInsert = fqn; } + else if (!isReferencedTo(referenceExpression, targetElement)) { + try { + referenceExpression.bindToElement(targetElement); + } + catch (IncorrectOperationException e) { + // failed to bind + } + if (!referenceExpression.isValid() || !isReferencedTo(referenceExpression, targetElement)) { + toInsert = fqn; + } + } } + catch (IncorrectOperationException ignored) {} } if (toInsert == null) toInsert = ""; diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index 614f204c6a95..fa92d548a366 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -699,8 +699,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { final PsiElement chosenAnchor = chooseAnchor(settings.isReplaceAllOccurrences(), hasWriteAccess, nonWrite, anchorStatementIfAll, anchorStatement); - variable = ApplicationManager.getApplication().runWriteAction( - introduce(project, expr, topLevelEditor, chosenAnchor, occurrences, settings)); + variable = introduce(project, expr, topLevelEditor, chosenAnchor, occurrences, settings); } finally { final RefactoringEventData afterData = new RefactoringEventData(); @@ -794,12 +793,12 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { return parent3 instanceof JspHolderMethod; } - public static Computable introduce(final Project project, - final PsiExpression expr, - final Editor editor, - final PsiElement anchorStatement, - final PsiExpression[] occurrences, - final IntroduceVariableSettings settings) { + public static PsiVariable introduce(final Project project, + final PsiExpression expr, + final Editor editor, + final PsiElement anchorStatement, + final PsiExpression[] occurrences, + final IntroduceVariableSettings settings) { final PsiElement container = anchorStatement.getParent(); PsiElement child = anchorStatement; final boolean isInsideLoop = RefactoringUtil.isLoopOrIf(container); @@ -841,9 +840,9 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { final PsiCodeBlock newDeclarationScope = PsiTreeUtil.getParentOfType(container, PsiCodeBlock.class, false); final FieldConflictsResolver fieldConflictsResolver = new FieldConflictsResolver(settings.getEnteredName(), newDeclarationScope); - return new Computable() { + SmartPsiElementPointer pointer = ApplicationManager.getApplication().runWriteAction(new Computable> () { @Override - public PsiVariable compute() { + public SmartPsiElementPointer compute() { try { PsiStatement statement = null; if (!isInsideLoop && deleteSelf) { @@ -913,7 +912,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { PsiVariable var = (PsiVariable) declaration.getDeclaredElements()[0]; PsiUtil.setModifierProperty(var, PsiModifier.FINAL, settings.isDeclareFinal()); fieldConflictsResolver.fix(); - return var; + return SmartPointerManager.getInstance(project).createSmartPsiElementPointer(var); } catch (IncorrectOperationException e) { LOG.error(e); } @@ -945,7 +944,8 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { } return (PsiDeclarationStatement) container.addBefore(declaration, anchor); } - }; + }); + return pointer != null ? pointer.getElement() : null; } private static PsiType stripNullabilityAnnotationsFromTargetType(SmartTypePointer selectedType, final Project project) { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java index c6ad929835b0..a53c51acc6c8 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java @@ -395,10 +395,19 @@ public class JavaVariableInplaceIntroducer extends AbstractJavaInplaceIntroducer @Override protected PsiVariable createFieldToStartTemplateOn(String[] names, PsiType psiType) { - final PsiVariable variable = ApplicationManager.getApplication().runWriteAction( - IntroduceVariableBase.introduce(myProject, myExpr, myEditor, myChosenAnchor.getElement(), getOccurrences(), mySettings)); + PsiVariable variable = IntroduceVariableBase.introduce(myProject, myExpr, myEditor, myChosenAnchor.getElement(), getOccurrences(), mySettings); + final PsiDeclarationStatement declarationStatement = PsiTreeUtil.getParentOfType(variable, PsiDeclarationStatement.class); + myPointer = declarationStatement != null ? SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(declarationStatement) : null; + myEditor.putUserData(ReassignVariableUtil.DECLARATION_KEY, myPointer); + setAdvertisementText(getAdvertisementText(declarationStatement, variable.getType(), myHasTypeSuggestion)); + PsiDocumentManager.getInstance(myProject).doPostponedOperationsAndUnblockDocument(myEditor.getDocument()); + final PsiVariable restoredVar = getVariable(); + if (restoredVar != null) { + variable = restoredVar; + } + if (isReplaceAllOccurrences()) { List occurrences = new ArrayList<>(); ReferencesSearch.search(variable).forEach(reference -> { @@ -407,10 +416,6 @@ public class JavaVariableInplaceIntroducer extends AbstractJavaInplaceIntroducer setOccurrenceMarkers(occurrences); } - final PsiDeclarationStatement declarationStatement = PsiTreeUtil.getParentOfType(variable, PsiDeclarationStatement.class); - myPointer = declarationStatement != null ? SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(declarationStatement) : null; - myEditor.putUserData(ReassignVariableUtil.DECLARATION_KEY, myPointer); - setAdvertisementText(getAdvertisementText(declarationStatement, variable.getType(), myHasTypeSuggestion)); final PsiIdentifier identifier = variable.getNameIdentifier(); if (identifier != null) { myEditor.getCaretModel().moveToOffset(identifier.getTextOffset()); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterAsLongStreamMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterAsLongStreamMap.java new file mode 100644 index 000000000000..54ce38e4db2a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterAsLongStreamMap.java @@ -0,0 +1,9 @@ +// "Merge 'asLongStream' call and 'map' call" "true" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> (String)cs).mapToInt(String::length).mapToLong(i -> (long) i * 2).boxed().forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterBoxedForEach.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterBoxedForEach.java new file mode 100644 index 000000000000..d2d8a82224de --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterBoxedForEach.java @@ -0,0 +1,9 @@ +// "Merge 'boxed' call and 'forEach' call" "true" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> (String)cs).mapToInt(String::length).asLongStream().map(x -> x*2).forEach((l) -> System.out.println((Long) l)); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapBoxed.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapBoxed.java new file mode 100644 index 000000000000..6f11313cefb4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapBoxed.java @@ -0,0 +1,9 @@ +// "Merge 'map' call and 'boxed' call" "true" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> (String)cs).mapToInt(String::length).asLongStream().mapToObj(x -> (Long) (x * 2)).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapForEach.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapForEach.java new file mode 100644 index 000000000000..26e0d0f5d22f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapForEach.java @@ -0,0 +1,8 @@ +// "Inline 'map' body into the next 'forEach' call" "true" +import java.util.List; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> cs.subSequence(1, 5)).forEach((charSequence) -> System.out.println(charSequence.length())); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapMap.java new file mode 100644 index 000000000000..b8d02f286f7c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapMap.java @@ -0,0 +1,8 @@ +// "Inline 'map' body into the next 'map' call" "true" +import java.util.List; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> cs.subSequence(1, 5).length()).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapMapExpr.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapMapExpr.java new file mode 100644 index 000000000000..b8d02f286f7c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapMapExpr.java @@ -0,0 +1,8 @@ +// "Inline 'map' body into the next 'map' call" "true" +import java.util.List; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> cs.subSequence(1, 5).length()).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapMapMR.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapMapMR.java new file mode 100644 index 000000000000..c0fd79876619 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapMapMR.java @@ -0,0 +1,8 @@ +// "Inline 'map' body into the next 'map' call" "true" +import java.util.List; + +public class Main { + public static void test(List list) { + list.stream().map((cs) -> cs.subSequence(1, 5).length()).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapMapToInt.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapMapToInt.java new file mode 100644 index 000000000000..51f09ebafda9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapMapToInt.java @@ -0,0 +1,9 @@ +// "Inline 'map' body into the next 'mapToInt' call" "true" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().mapToInt((cs) -> ((String) cs).length()).asLongStream().map(x -> x*2).boxed().forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapToIntAsLongStream.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapToIntAsLongStream.java new file mode 100644 index 000000000000..386a1c9a07ab --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapToIntAsLongStream.java @@ -0,0 +1,9 @@ +// "Merge 'mapToInt' call and 'asLongStream' call" "true" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> (String)cs).mapToLong(s -> (long) s.length()).map(x -> x*2).boxed().forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapToIntFlatMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapToIntFlatMap.java new file mode 100644 index 000000000000..84a406fbdd60 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/afterMapToIntFlatMap.java @@ -0,0 +1,9 @@ +// "Inline 'mapToInt' body into the next 'flatMap' call" "true" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> (String)cs).flatMapToInt(s1 -> IntStream.range(0, s1.length())).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeAsLongStreamMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeAsLongStreamMap.java new file mode 100644 index 000000000000..b4da3d8be0b0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeAsLongStreamMap.java @@ -0,0 +1,9 @@ +// "Merge 'asLongStream' call and 'map' call" "true" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> (String)cs).mapToInt(String::length).asLongStream().map(x -> x*2).boxed().forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeBoxedForEach.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeBoxedForEach.java new file mode 100644 index 000000000000..236777cd7dcf --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeBoxedForEach.java @@ -0,0 +1,9 @@ +// "Merge 'boxed' call and 'forEach' call" "true" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> (String)cs).mapToInt(String::length).asLongStream().map(x -> x*2).boxed().forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeFlatMapForEach.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeFlatMapForEach.java new file mode 100644 index 000000000000..bcfaff7752f8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeFlatMapForEach.java @@ -0,0 +1,9 @@ +// "Inline 'flatMap' body into the next 'forEach' call" "false" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> (String)cs).mapToInt(String::length).flatMap(s -> IntStream.range(0, s)).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapBoxed.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapBoxed.java new file mode 100644 index 000000000000..abe11d46b724 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapBoxed.java @@ -0,0 +1,9 @@ +// "Merge 'map' call and 'boxed' call" "true" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> (String)cs).mapToInt(String::length).asLongStream().map(x -> x*2).boxed().forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapForEach.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapForEach.java new file mode 100644 index 000000000000..1f915897ee6e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapForEach.java @@ -0,0 +1,8 @@ +// "Inline 'map' body into the next 'forEach' call" "true" +import java.util.List; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> cs.subSequence(1, 5)).map(CharSequence::length).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMap.java new file mode 100644 index 000000000000..231cc075b2db --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMap.java @@ -0,0 +1,8 @@ +// "Inline 'map' body into the next 'map' call" "true" +import java.util.List; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> cs.subSequence(1, 5)).map(cs -> cs.length()).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMapExpr.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMapExpr.java new file mode 100644 index 000000000000..c85780d55a36 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMapExpr.java @@ -0,0 +1,10 @@ +// "Inline 'map' body into the next 'map' call" "true" +import java.util.List; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> { + return cs.subSequence(1, 5); + }).map(cs -> cs.length()).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMapMR.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMapMR.java new file mode 100644 index 000000000000..a5651a40f0eb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMapMR.java @@ -0,0 +1,8 @@ +// "Inline 'map' body into the next 'map' call" "true" +import java.util.List; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> cs.subSequence(1, 5)).map(CharSequence::length).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMapToInt.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMapToInt.java new file mode 100644 index 000000000000..62f169782191 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMapToInt.java @@ -0,0 +1,9 @@ +// "Inline 'map' body into the next 'mapToInt' call" "true" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> (String)cs).mapToInt(String::length).asLongStream().map(x -> x*2).boxed().forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMapTwoExpr.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMapTwoExpr.java new file mode 100644 index 000000000000..ef277ee38ef9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapMapTwoExpr.java @@ -0,0 +1,11 @@ +// "Inline 'map' body into the next 'map' call" "false" +import java.util.List; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> { + cs = cs.subSequence(0, 10); + return cs.subSequence(1, 5); + }).map(cs -> cs.length()).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapToIntAsLongStream.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapToIntAsLongStream.java new file mode 100644 index 000000000000..a95324d26a1f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapToIntAsLongStream.java @@ -0,0 +1,9 @@ +// "Merge 'mapToInt' call and 'asLongStream' call" "true" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> (String)cs).mapToInt(String::length).asLongStream().map(x -> x*2).boxed().forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapToIntFlatMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapToIntFlatMap.java new file mode 100644 index 000000000000..3bd66dd69a3b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap/beforeMapToIntFlatMap.java @@ -0,0 +1,9 @@ +// "Inline 'mapToInt' body into the next 'flatMap' call" "true" +import java.util.List; +import java.util.stream.IntStream; + +public class Main { + public static void test(List list) { + list.stream().map(cs -> (String)cs).mapToInt(String::length).flatMap(s -> IntStream.range(0, s)).forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/NullLiteralArgumentDoesntReportedWhenMethodOnlyThrowAnException.java b/java/java-tests/testData/inspection/dataFlow/fixture/NullLiteralArgumentDoesntReportedWhenMethodOnlyThrowAnException.java new file mode 100644 index 000000000000..aff8882cc70a --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/NullLiteralArgumentDoesntReportedWhenMethodOnlyThrowAnException.java @@ -0,0 +1,10 @@ +class Test { + + void m() { + throwAnException(null); + } + + static void throwAnException(String arg) { + throw new RuntimeException(); + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/brokenFormattingWithInValidation.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/brokenFormattingWithInValidation.java new file mode 100644 index 000000000000..06b06cbd5f32 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/brokenFormattingWithInValidation.java @@ -0,0 +1,10 @@ +class C { + void sort(int[] array) { + int j; + for (int i = 0; i < array.length; i++) { + j = 0; + while (j>array[i]) + + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/brokenFormattingWithInValidation_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/brokenFormattingWithInValidation_after.java new file mode 100644 index 000000000000..b36d03646293 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/brokenFormattingWithInValidation_after.java @@ -0,0 +1,10 @@ +class C { + void sort(int[] array) { + int j; + for (int i = 0; i < array.length; i++) { + j = 0; + while (j array[i];&&(array[j] > array[i]) + + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/intention/InlineStreamMapActionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/intention/InlineStreamMapActionTest.java new file mode 100644 index 000000000000..a96409ec6b74 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/intention/InlineStreamMapActionTest.java @@ -0,0 +1,28 @@ +/* + * 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.codeInsight.intention; + +import com.intellij.codeInsight.daemon.LightIntentionActionTestCase; + +public class InlineStreamMapActionTest extends LightIntentionActionTestCase { + + public void test() throws Exception { doAllTests(); } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/inlineStreamMap"; + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index 8d3e4c50b620..eb2a56ad9d22 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -405,4 +405,5 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase { public void testNullLiteralAndInferredMethodContract() { doTest(); } + public void testNullLiteralArgumentDoesntReportedWhenMethodOnlyThrowAnException() { doTest(); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionProfileTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionProfileTest.java index 1600bfa069f4..975f15ccfe43 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionProfileTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionProfileTest.java @@ -27,7 +27,6 @@ import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.WriteExternalException; import com.intellij.profile.Profile; import com.intellij.profile.codeInspection.InspectionProfileManager; -import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; import com.intellij.profile.codeInspection.ui.header.InspectionToolsConfigurable; import com.intellij.psi.PsiModifier; @@ -43,8 +42,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import static com.intellij.profile.ProfileEx.serializeProfile; -import static com.intellij.testFramework.PlatformTestUtil.assertElementsEqual; +import static com.intellij.testFramework.Assertions.assertThat; /** * @author Anna.Kozlova @@ -80,11 +78,11 @@ public class InspectionProfileTest extends LightIdeaTestCase { profile.readExternal(element); final ModifiableModel model = profile.getModifiableModel(); model.commit(); - assertElementsEqual(element, serializeProfile(profile)); + assertThat(profile.writeScheme()).isEqualTo(element); } private static InspectionProfileImpl createProfile() { - return new InspectionProfileImpl(PROFILE, InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), InspectionProfileImpl.getDefaultProfile(), null); + return new InspectionProfileImpl(PROFILE, InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), InspectionProfileImpl.getBaseProfile(), null); } private static InspectionProfileImpl createProfile(@NotNull InspectionProfileImpl base) { return new InspectionProfileImpl(PROFILE, InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), base, null); @@ -100,7 +98,7 @@ public class InspectionProfileTest extends LightIdeaTestCase { //normally on open project profile wrappers are init for both managers profileManager.updateProfile(localProfile); InspectionProfileImpl profile = new InspectionProfileImpl(PROFILE, InspectionToolRegistrar.getInstance(), projectProfileManager, - InspectionProfileImpl.getDefaultProfile(), null); + InspectionProfileImpl.getBaseProfile(), null); projectProfileManager.updateProfile(profile); projectProfileManager.setRootProfile(profile.getName()); @@ -150,7 +148,7 @@ public class InspectionProfileTest extends LightIdeaTestCase { ModifiableModel model = profile.getModifiableModel(); model.commit(); - assertElementsEqual(loadProfile(), serializeProfile(profile)); + assertThat(profile.writeScheme()).isEqualTo(loadProfile()); } private static Element loadProfile() throws IOException, JDOMException { @@ -206,7 +204,7 @@ public class InspectionProfileTest extends LightIdeaTestCase { profile.readExternal(element); final ModifiableModel model = profile.getModifiableModel(); model.commit(); - assertElementsEqual(element, serializeProfile(profile)); + assertThat(profile.writeScheme()).isEqualTo(element); } public void testMergeUnusedDeclarationAndUnusedSymbol() throws Exception { @@ -218,7 +216,7 @@ public class InspectionProfileTest extends LightIdeaTestCase { profile.readExternal(element); ModifiableModel model = profile.getModifiableModel(); model.commit(); - assertElementsEqual(element, serializeProfile(profile)); + assertThat(profile.writeScheme()).isEqualTo(element); //settings to merge @@ -290,7 +288,7 @@ public class InspectionProfileTest extends LightIdeaTestCase { ""; assertEquals(mergedText, serialize(profile)); - Element toImportElement = serializeProfile(profile); + Element toImportElement = profile.writeScheme(); final InspectionProfileImpl importedProfile = InspectionToolsConfigurable.importInspectionProfile(toImportElement, InspectionProfileManager.getInstance(), getProject(), null); @@ -300,9 +298,9 @@ public class InspectionProfileTest extends LightIdeaTestCase { profile.readExternal(mergedElement); model = profile.getModifiableModel(); model.commit(); - assertElementsEqual(mergedElement, serializeProfile(profile)); + assertThat(profile.writeScheme()).isEqualTo(mergedElement); - assertElementsEqual(mergedElement, serializeProfile(importedProfile)); + assertThat(importedProfile.writeScheme()).isEqualTo(mergedElement); } public void testStoredMemberVisibility() throws Exception { @@ -510,7 +508,7 @@ public class InspectionProfileTest extends LightIdeaTestCase { "", serialize(profile)); - Element element = serializeProfile(profile); + Element element = profile.writeScheme(); list.add(createTool("bar", true)); list.add(createTool("disabled", false)); @@ -537,7 +535,7 @@ public class InspectionProfileTest extends LightIdeaTestCase { } private static String serialize(InspectionProfileImpl profile) throws WriteExternalException { - return JDOMUtil.writeElement(serializeProfile(profile)); + return JDOMUtil.writeElement(profile.writeScheme()); } private static InspectionProfileImpl createProfile(@NotNull InspectionToolRegistrar registrar) { @@ -581,7 +579,7 @@ public class InspectionProfileTest extends LightIdeaTestCase { } public void testDoNotInstantiateOnSave() throws Exception { - InspectionProfileImpl profile = new InspectionProfileImpl("profile", InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), InspectionProfileImpl.getDefaultProfile(), null); + InspectionProfileImpl profile = new InspectionProfileImpl("profile", InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), InspectionProfileImpl.getBaseProfile(), null); assertEquals(0, countInitializedTools(profile)); InspectionToolWrapper[] toolWrappers = profile.getInspectionTools(null); assertTrue(toolWrappers.length > 0); @@ -596,7 +594,7 @@ public class InspectionProfileTest extends LightIdeaTestCase { profile.enableTool(id, getProject()); } assertEquals(0, countInitializedTools(profile)); - serializeProfile(profile); + profile.writeScheme(); List initializedTools = getInitializedTools(profile); if (initializedTools.size() > 0) { for (InspectionToolWrapper initializedTool : initializedTools) { @@ -619,20 +617,6 @@ public class InspectionProfileTest extends LightIdeaTestCase { assertEquals(1, countInitializedTools(foo)); } - public void testPreserveCompatibility() throws Exception { - InspectionProfileImpl foo = new InspectionProfileImpl("foo", InspectionToolRegistrar.getInstance(), InspectionProjectProfileManager.getInstance(getProject())); - String test = "\n" + - " "; - foo.readExternal(JDOMUtil.loadDocument(test).getRootElement()); - foo.initInspectionTools(getProject()); - assertEquals(test, JDOMUtil.writeElement(serializeProfile(foo))); - } - public static int countInitializedTools(@NotNull Profile foo) { return getInitializedTools((InspectionProfileImpl)foo).size(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionSchemeTest.kt b/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionSchemeTest.kt index 8709ee796ef3..58880e3e19fc 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionSchemeTest.kt +++ b/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionSchemeTest.kt @@ -41,7 +41,7 @@ class InspectionSchemeTest { @Test fun loadSchemes() { val schemeFile = fsRule.fs.getPath("inspection/Bar.xml") val schemeData = """ - + """.trimIndent() @@ -51,7 +51,7 @@ class InspectionSchemeTest { profileManager.forceInitProfiles(true) profileManager.initProfiles() - assertThat(profileManager.profiles).hasSize(2) + assertThat(profileManager.profiles).hasSize(1) val scheme = profileManager.profiles.first() as InspectionProfileImpl assertThat(scheme.name).isEqualTo("Bar") @@ -61,5 +61,11 @@ class InspectionSchemeTest { assertThat(schemeFile.readText()).isEqualTo(schemeData) profileManager.profiles + + schemeManagerFactory.process { + it.reload() + } + + assertThat(profileManager.profiles).hasSize(1) } } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceVariableTest.java index 5e9ca964059c..44a86d4a2388 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceVariableTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceVariableTest.java @@ -205,6 +205,15 @@ public class InplaceIntroduceVariableTest extends AbstractJavaInplaceIntroduceTe doTestReplaceChoice(OccurrencesChooser.ReplaceChoice.ALL); } + public void testBrokenFormattingWithInValidation() throws Exception { + doTest(new Pass() { + @Override + public void pass(AbstractInplaceIntroducer introducer) { + type("bool"); + } + }); + } + public void testStopEditing() { doTestStopEditing(new Pass() { @Override diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java index 8c9619b112b5..19ec879a4f35 100644 --- a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java @@ -60,7 +60,7 @@ public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase return ActionHint.parse(file, contents); } - private static void doTestFor(final String testName, final QuickFixTestCase quickFixTestCase) { + private static void doTestFor(@NotNull String testName, @NotNull QuickFixTestCase quickFixTestCase) { final String relativePath = ObjectUtils.notNull(quickFixTestCase.getBasePath(), "") + "/" + BEFORE_PREFIX + testName; final String testFullPath = quickFixTestCase.getTestDataPath().replace(File.separatorChar, '/') + relativePath; final File testFile = new File(testFullPath); @@ -204,7 +204,7 @@ public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase return files; } - protected void doSingleTest(String fileSuffix) { + protected void doSingleTest(@NotNull String fileSuffix) { doTestFor(fileSuffix, createWrapper()); } @@ -212,10 +212,12 @@ public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase doTestFor(fileSuffix, createWrapper(testDataPath)); } + @NotNull protected QuickFixTestCase createWrapper() { return createWrapper(null); } + @NotNull protected QuickFixTestCase createWrapper(final String testDataPath) { return new QuickFixTestCase() { public String myTestDataPath = testDataPath; @@ -225,6 +227,7 @@ public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase return LightQuickFixTestCase.this.getBasePath(); } + @NotNull @Override public String getTestDataPath() { if (myTestDataPath == null) { @@ -240,27 +243,27 @@ public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase } @Override - public void beforeActionStarted(String testName, String contents) { + public void beforeActionStarted(@NotNull String testName, @NotNull String contents) { LightQuickFixTestCase.this.beforeActionStarted(testName, contents); } @Override - public void afterActionCompleted(String testName, String contents) { + public void afterActionCompleted(@NotNull String testName, @NotNull String contents) { LightQuickFixTestCase.this.afterActionCompleted(testName, contents); } @Override - public void doAction(ActionHint actionHint, String testFullPath, String testName) throws Exception { + public void doAction(@NotNull ActionHint actionHint, @NotNull String testFullPath, @NotNull String testName) throws Exception { LightQuickFixTestCase.this.doAction(actionHint, testFullPath, testName); } @Override - public void checkResultByFile(String s, @NotNull String expectedFilePath, boolean b) throws Exception { - LightQuickFixTestCase.this.checkResultByFile(s, expectedFilePath, b); + public void checkResultByFile(@NotNull String message, @NotNull String expectedFilePath, boolean ignoreTrailingSpaces) throws Exception { + LightQuickFixTestCase.this.checkResultByFile(message, expectedFilePath, ignoreTrailingSpaces); } @Override - public IntentionAction findActionWithText(String text) { + public IntentionAction findActionWithText(@NotNull String text) { return LightQuickFixTestCase.this.findActionWithText(text); } @@ -270,7 +273,7 @@ public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase } @Override - public void invoke(IntentionAction action) { + public void invoke(@NotNull IntentionAction action) { LightQuickFixTestCase.invoke(action); } @@ -287,7 +290,7 @@ public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase } @Override - public void configureFromFileText(String name, String contents) throws IOException { + public void configureFromFileText(@NotNull String name, @NotNull String contents) throws IOException { LightPlatformCodeInsightTestCase.configureFromFileText(name, contents, true); } @@ -313,6 +316,7 @@ public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase return getAvailableActions(getEditor(), getFile()); } + @NotNull public static List getAvailableActions(@NotNull Editor editor, @NotNull PsiFile file) { return CodeInsightTestFixtureImpl.getAvailableIntentions(editor, file); } diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/QuickFixTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/QuickFixTestCase.java index 8c00ae4149dc..e69b636fecd6 100644 --- a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/QuickFixTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/QuickFixTestCase.java @@ -31,24 +31,25 @@ import java.util.List; public interface QuickFixTestCase { String getBasePath(); + @NotNull String getTestDataPath(); @NotNull ActionHint parseActionHintImpl(@NotNull PsiFile file, @NotNull String contents); - void beforeActionStarted(String testName, String contents); + void beforeActionStarted(@NotNull String testName, @NotNull String contents); - void afterActionCompleted(String testName, String contents); + void afterActionCompleted(@NotNull String testName, @NotNull String contents); - void doAction(ActionHint actionHint, String testFullPath, String testName) throws Exception; + void doAction(@NotNull ActionHint actionHint, @NotNull String testFullPath, @NotNull String testName) throws Exception; - void checkResultByFile(String s, @NotNull String expectedFilePath, boolean b) throws Exception; + void checkResultByFile(@NotNull String message, @NotNull String expectedFilePath, boolean ignoreTrailingSpaces) throws Exception; - IntentionAction findActionWithText(String text); + IntentionAction findActionWithText(@NotNull String text); boolean shouldBeAvailableAfterExecution(); - void invoke(IntentionAction action); + void invoke(@NotNull IntentionAction action); @NotNull List doHighlighting(); @@ -58,7 +59,7 @@ public interface QuickFixTestCase { void bringRealEditorBack(); - void configureFromFileText(String name, String contents) throws Throwable; + void configureFromFileText(@NotNull String name, @NotNull String contents) throws Throwable; PsiFile getFile(); diff --git a/platform/analysis-api/src/com/intellij/profile/Profile.java b/platform/analysis-api/src/com/intellij/profile/Profile.java index 08e65fc15cc3..163875cb8423 100644 --- a/platform/analysis-api/src/com/intellij/profile/Profile.java +++ b/platform/analysis-api/src/com/intellij/profile/Profile.java @@ -17,7 +17,6 @@ package com.intellij.profile; import com.intellij.openapi.options.Scheme; import com.intellij.util.xmlb.annotations.Transient; -import org.jdom.Element; import org.jetbrains.annotations.NotNull; /** @@ -25,8 +24,6 @@ import org.jetbrains.annotations.NotNull; * Date: 20-Nov-2005 */ public interface Profile extends Comparable, Scheme { - void copyFrom(@NotNull Profile profile); - @Transient boolean isProjectLevel(); @@ -42,8 +39,4 @@ public interface Profile extends Comparable, Scheme { @NotNull ProfileManager getProfileManager(); - - void readExternal(Element element); - - void writeExternal(Element element); } diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/InspectionProfileConvertor.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/InspectionProfileConvertor.java index f45ffc640444..63fadcb0afa5 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/InspectionProfileConvertor.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/InspectionProfileConvertor.java @@ -26,13 +26,13 @@ import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.io.FileUtil; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.SeverityProvider; -import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -50,7 +50,6 @@ public class InspectionProfileConvertor { @NonNls private static final String NAME_ATT = "name"; @NonNls private static final String VERSION_ATT = "version"; - @NonNls private static final String PROFILE_NAME_ATT = "profile_name"; @NonNls private static final String OPTION_TAG = "option"; @NonNls private static final String DISPLAY_LEVEL_MAP_OPTION = "DISPLAY_LEVEL_MAP"; @NonNls protected static final String VALUE_ATT = "value"; @@ -110,11 +109,9 @@ public class InspectionProfileConvertor { return; } try { - Document doc = JDOMUtil.loadDocument(files[0]); - Element root = doc.getRootElement(); + Element root = JDOMUtil.load(files[0]); if (root.getAttributeValue(VERSION_ATT) == null){ - root.setAttribute(PROFILE_NAME_ATT, OLD_DEFAUL_PROFILE); - JDOMUtil.writeDocument(doc, new File(profileDirectory, OLD_DEFAUL_PROFILE + XML_EXTENSION), "\n"); + JDOMUtil.writeParent(root, new FileOutputStream(new File(profileDirectory, OLD_DEFAUL_PROFILE + XML_EXTENSION)), "\n"); FileUtil.delete(files[0]); } } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java index ac9028837678..0556319665dd 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java @@ -33,10 +33,7 @@ import com.intellij.openapi.util.*; import com.intellij.profile.ProfileEx; import com.intellij.profile.ProfileManager; import com.intellij.profile.codeInspection.InspectionProfileManager; -import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; -import com.intellij.profile.codeInspection.ProjectInspectionProfileManagerKt; import com.intellij.profile.codeInspection.SeverityProvider; -import com.intellij.project.ProjectKt; import com.intellij.psi.PsiElement; import com.intellij.psi.search.scope.packageSet.NamedScope; import com.intellij.util.ArrayUtil; @@ -104,7 +101,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, public InspectionProfileImpl(@NotNull String profileName, @NotNull InspectionToolRegistrar registrar, @NotNull ProfileManager profileManager) { - this(profileName, registrar, profileManager, getDefaultProfile(), null); + this(profileName, registrar, profileManager, getBaseProfile(), null); } public InspectionProfileImpl(@NotNull @NonNls String profileName) { @@ -128,7 +125,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, @NotNull InspectionToolRegistrar registrar, @NotNull ProfileManager profileManager, @Nullable SchemeDataHolder dataHolder) { - this(profileName, registrar, profileManager, getDefaultProfile(), dataHolder); + this(profileName, registrar, profileManager, getBaseProfile(), dataHolder); } @NotNull @@ -166,7 +163,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, } @NotNull - public static InspectionProfileImpl getDefaultProfile() { + public static InspectionProfileImpl getBaseProfile() { return InspectionProfileImplHolder.DEFAULT_PROFILE; } @@ -281,26 +278,15 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, @NotNull public Element writeScheme() { - if (myDataHolder != null) { - return myDataHolder.read(); - } - - Element element = new Element("profile"); - Element result = isProjectLevel() ? element.setAttribute("version", "1.0") : element.setAttribute("profile_name", getName()); - serializeInto(result, false); - - if (isProjectLevel() && ProjectKt.isDirectoryBased(((ProjectInspectionProfileManager)myProfileManager).getProject())) { - return new Element("component").setAttribute("name", "InspectionProjectProfileManager").addContent(result); - } - return result; + return myDataHolder == null ? super.writeScheme() : myDataHolder.read(); } @Override - public void serializeInto(@NotNull Element element, boolean preserveCompatibility) { + public void writeExternal(@NotNull Element element) { // must be first - compatibility element.setAttribute(VERSION_TAG, VALID_VERSION); - super.serializeInto(element, preserveCompatibility); + super.writeExternal(element); synchronized (myLock) { if (!myInitialized) { @@ -857,24 +843,23 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, initInspectionTools(project); for (Element scopeElement : scopes.getChildren(SCOPE)) { - final String profile = scopeElement.getAttributeValue(ProjectInspectionProfileManagerKt.PROFILE); - if (profile != null) { - final InspectionProfileImpl inspectionProfile = (InspectionProfileImpl)getProfileManager().getProfile(profile); - if (inspectionProfile != null) { - final NamedScope scope = getProfileManager().getScopesManager().getScope(scopeElement.getAttributeValue(NAME)); - if (scope != null) { - for (InspectionToolWrapper toolWrapper : inspectionProfile.getInspectionTools(null)) { - final HighlightDisplayKey key = HighlightDisplayKey.find(toolWrapper.getShortName()); - try { - InspectionToolWrapper toolWrapperCopy = copyToolSettings(toolWrapper); - HighlightDisplayLevel errorLevel = inspectionProfile.getErrorLevel(key, null, project); - getTools(toolWrapper.getShortName(), project).addTool(scope, toolWrapperCopy, inspectionProfile.isToolEnabled(key), errorLevel); - } - catch (Exception e) { - LOG.error(e); - } - } - } + final String profile = scopeElement.getAttributeValue(PROFILE); + InspectionProfileImpl inspectionProfile = profile == null ? null : (InspectionProfileImpl)getProfileManager().getProfile(profile); + NamedScope scope = inspectionProfile == null ? null : getProfileManager().getScopesManager().getScope(scopeElement.getAttributeValue(NAME)); + if (scope == null) { + continue; + } + + for (InspectionToolWrapper toolWrapper : inspectionProfile.getInspectionTools(null)) { + final HighlightDisplayKey key = HighlightDisplayKey.find(toolWrapper.getShortName()); + try { + InspectionToolWrapper toolWrapperCopy = copyToolSettings(toolWrapper); + HighlightDisplayLevel errorLevel = inspectionProfile.getErrorLevel(key, null, project); + getTools(toolWrapper.getShortName(), project) + .addTool(scope, toolWrapperCopy, inspectionProfile.isToolEnabled(key), errorLevel); + } + catch (Exception e) { + LOG.error(e); } } } diff --git a/platform/analysis-impl/src/com/intellij/profile/ProfileEx.java b/platform/analysis-impl/src/com/intellij/profile/ProfileEx.java index 9ff4b6785519..6060227b2c09 100644 --- a/platform/analysis-impl/src/com/intellij/profile/ProfileEx.java +++ b/platform/analysis-impl/src/com/intellij/profile/ProfileEx.java @@ -15,7 +15,8 @@ */ package com.intellij.profile; -import com.intellij.profile.codeInspection.ProjectInspectionProfileManagerKt; +import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; +import com.intellij.project.ProjectKt; import com.intellij.util.xmlb.SmartSerializer; import com.intellij.util.xmlb.annotations.OptionTag; import com.intellij.util.xmlb.annotations.Transient; @@ -29,6 +30,7 @@ import org.jetbrains.annotations.NotNull; public abstract class ProfileEx implements Profile { public static final String SCOPE = "scope"; public static final String NAME = "name"; + public static final String PROFILE = "profile"; private final SmartSerializer mySerializer; @@ -84,18 +86,12 @@ public abstract class ProfileEx implements Profile { myProfileManager = profileManager; } - @Override public void readExternal(Element element) { mySerializer.readExternal(this, element); } - public void serializeInto(@NotNull Element element, boolean preserveCompatibility) { - mySerializer.writeExternal(this, element, preserveCompatibility); - } - - @Override - public final void writeExternal(Element element) { - serializeInto(element, true); + public void writeExternal(@NotNull Element element) { + mySerializer.writeExternal(this, element, false); } public boolean equals(Object o) { @@ -114,15 +110,21 @@ public abstract class ProfileEx implements Profile { return 0; } - @Override - public final void copyFrom(@NotNull Profile profile) { - readExternal(serializeProfile(profile)); + public final void copyFrom(@NotNull ProfileEx profile) { + readExternal(profile.writeScheme()); } @NotNull - public static Element serializeProfile(@NotNull Profile profile) { - Element result = new Element(ProjectInspectionProfileManagerKt.PROFILE); - profile.writeExternal(result); - return result; + public Element writeScheme() { + Element element = new Element(PROFILE); + if (isProjectLevel()) { + element.setAttribute("version", "1.0"); + } + writeExternal(element); + + if (isProjectLevel() && ProjectKt.isDirectoryBased(((ProjectInspectionProfileManager)myProfileManager).getProject())) { + return new Element("component").setAttribute("name", "InspectionProjectProfileManager").addContent(element); + } + return element; } } diff --git a/platform/analysis-impl/src/com/intellij/profile/codeInspection/ProjectInspectionProfileManager.kt b/platform/analysis-impl/src/com/intellij/profile/codeInspection/ProjectInspectionProfileManager.kt index d0593856fc8a..f6a759bfbe13 100644 --- a/platform/analysis-impl/src/com/intellij/profile/codeInspection/ProjectInspectionProfileManager.kt +++ b/platform/analysis-impl/src/com/intellij/profile/codeInspection/ProjectInspectionProfileManager.kt @@ -33,6 +33,7 @@ import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.text.StringUtil import com.intellij.packageDependencies.DependencyValidationManager import com.intellij.profile.Profile +import com.intellij.profile.ProfileEx import com.intellij.project.isDirectoryBased import com.intellij.psi.search.scope.packageSet.NamedScopeManager import com.intellij.psi.search.scope.packageSet.NamedScopesHolder @@ -50,8 +51,6 @@ import org.jetbrains.concurrency.runAsync import java.util.* import java.util.function.Function -const val PROFILE = "profile" - private const val VERSION = "1.0" private const val SCOPE = "scope" private const val NAME = "name" @@ -99,7 +98,7 @@ class ProjectInspectionProfileManager(val project: Project, attributeProvider: Function, isBundled: Boolean): InspectionProfileImpl { val profile = InspectionProfileImpl(name, InspectionToolRegistrar.getInstance(), this@ProjectInspectionProfileManager, - InspectionProfileImpl.getDefaultProfile(), dataHolder) + InspectionProfileImpl.getBaseProfile(), dataHolder) profile.isProjectLevel = true return profile } @@ -307,8 +306,8 @@ class ProjectInspectionProfileManager(val project: Project, currentScheme = schemeManager.allSchemes.firstOrNull() if (currentScheme == null) { currentScheme = InspectionProfileImpl(PROJECT_DEFAULT_PROFILE_NAME, InspectionToolRegistrar.getInstance(), this, - InspectionProfileImpl.getDefaultProfile(), null) - currentScheme.copyFrom(applicationProfileManager.currentProfile) + InspectionProfileImpl.getBaseProfile(), null) + currentScheme.copyFrom(applicationProfileManager.currentProfile as ProfileEx) currentScheme.isProjectLevel = true currentScheme.name = PROJECT_DEFAULT_PROFILE_NAME schemeManager.addScheme(currentScheme) diff --git a/platform/configuration-store-impl/src/SchemeManagerImpl.kt b/platform/configuration-store-impl/src/SchemeManagerImpl.kt index eb9b341f4316..a210200778f6 100644 --- a/platform/configuration-store-impl/src/SchemeManagerImpl.kt +++ b/platform/configuration-store-impl/src/SchemeManagerImpl.kt @@ -233,11 +233,11 @@ class SchemeManagerImpl(val fileSpec: String, val bytes = URLUtil.openStream(url).readBytes() lazyPreloadScheme(bytes, isUseOldFileNameSanitize) { name, parser -> val attributeProvider = Function { parser.getAttributeValue(null, it) } - val schemeName = name ?: (processor as LazySchemeProcessor).getName(attributeProvider) - val fileName = PathUtilRt.getFileName(url.path) val extension = getFileExtension(fileName, true) val externalInfo = ExternalInfo(fileName.substring(0, fileName.length - extension.length), extension) + + val schemeName = name ?: (processor as LazySchemeProcessor).getName(attributeProvider, externalInfo.fileNameWithoutExtension) externalInfo.schemeName = schemeName val scheme = (processor as LazySchemeProcessor).createScheme(SchemeDataHolderImpl(bytes, externalInfo), schemeName, attributeProvider, true) @@ -316,7 +316,7 @@ class SchemeManagerImpl(val fileSpec: String, processPendingCurrentSchemeName(scheme) } - messageBus?.let { it.connect().subscribe(VirtualFileManager.VFS_CHANGES, SchemeFileTracker()) } + messageBus?.connect()?.subscribe(VirtualFileManager.VFS_CHANGES, SchemeFileTracker()) return schemes.subList(newSchemesOffset, schemes.size) } @@ -438,7 +438,7 @@ class SchemeManagerImpl(val fileSpec: String, val bytes = input.readBytes() lazyPreloadScheme(bytes, isUseOldFileNameSanitize) { name, parser -> val attributeProvider = Function { parser.getAttributeValue(null, it) } - val schemeName = name ?: processor.getName(attributeProvider) + val schemeName = name ?: processor.getName(attributeProvider, fileNameWithoutExtension) if (!checkExisting(schemeName)) { return null } @@ -573,7 +573,7 @@ class SchemeManagerImpl(val fileSpec: String, var externalInfo: ExternalInfo? = schemeToInfo.get(scheme) val currentFileNameWithoutExtension = externalInfo?.fileNameWithoutExtension val parent = processor.writeScheme(scheme) - val element = if (parent is Element) parent else (parent as Document).detachRootElement() + val element = parent as? Element ?: (parent as Document).detachRootElement() if (element.isEmpty()) { externalInfo?.scheduleDelete() return @@ -685,7 +685,7 @@ class SchemeManagerImpl(val fileSpec: String, val bundledScheme = readOnlyExternalizableSchemes.get(scheme.name) if (bundledScheme == null) { - if ((processor as? LazySchemeProcessor)?.let { it.isSchemeEqualToBundled(scheme) } ?: false) { + if ((processor as? LazySchemeProcessor)?.isSchemeEqualToBundled(scheme) ?: false) { externalInfo?.scheduleDelete() return true } @@ -875,9 +875,7 @@ class SchemeManagerImpl(val fileSpec: String, private fun collectExistingNames(schemes: Collection): Collection { val result = THashSet(schemes.size) - for (scheme in schemes) { - result.add(scheme.name) - } + schemes.mapTo(result) { it.name } return result } diff --git a/platform/core-api/src/com/intellij/openapi/util/Iconable.java b/platform/core-api/src/com/intellij/openapi/util/Iconable.java index 643223564c8d..b2de180119b0 100644 --- a/platform/core-api/src/com/intellij/openapi/util/Iconable.java +++ b/platform/core-api/src/com/intellij/openapi/util/Iconable.java @@ -15,7 +15,8 @@ */ package com.intellij.openapi.util; -import gnu.trove.TIntObjectHashMap; +import com.intellij.util.containers.ConcurrentIntObjectMap; +import com.intellij.util.containers.ContainerUtil; import org.intellij.lang.annotations.MagicConstant; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,24 +29,24 @@ public interface Iconable { @Deprecated int ICON_FLAG_OPEN = 0x0004; @Deprecated int ICON_FLAG_CLOSED = 0x0008; - @MagicConstant(flags = {ICON_FLAG_VISIBILITY, ICON_FLAG_OPEN, ICON_FLAG_CLOSED, ICON_FLAG_READ_STATUS}) + @MagicConstant(flags = {ICON_FLAG_VISIBILITY, ICON_FLAG_READ_STATUS}) @interface IconFlags {} Icon getIcon(@IconFlags int flags); class LastComputedIcon { - private static final Key> LAST_COMPUTED_ICON = Key.create("lastComputedIcon"); + private static final Key> LAST_COMPUTED_ICON = Key.create("lastComputedIcon"); @Nullable public static Icon get(@NotNull UserDataHolder holder, int flags) { - TIntObjectHashMap map = holder.getUserData(LAST_COMPUTED_ICON); + ConcurrentIntObjectMap map = holder.getUserData(LAST_COMPUTED_ICON); return map == null ? null : map.get(flags); } public static void put(@NotNull UserDataHolder holder, Icon icon, int flags) { - TIntObjectHashMap map = holder.getUserData(LAST_COMPUTED_ICON); + ConcurrentIntObjectMap map = holder.getUserData(LAST_COMPUTED_ICON); if (map == null) { - map = ((UserDataHolderEx)holder).putUserDataIfAbsent(LAST_COMPUTED_ICON, new TIntObjectHashMap()); + map = ((UserDataHolderEx)holder).putUserDataIfAbsent(LAST_COMPUTED_ICON, ContainerUtil.createConcurrentIntObjectMap()); } map.put(flags, icon); } diff --git a/platform/core-api/src/com/intellij/openapi/util/SimpleModificationTracker.java b/platform/core-api/src/com/intellij/openapi/util/SimpleModificationTracker.java index 91a933909066..b83dc9cfe765 100644 --- a/platform/core-api/src/com/intellij/openapi/util/SimpleModificationTracker.java +++ b/platform/core-api/src/com/intellij/openapi/util/SimpleModificationTracker.java @@ -15,7 +15,6 @@ */ package com.intellij.openapi.util; -import com.intellij.Patches; import com.intellij.util.xmlb.annotations.Transient; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; @@ -26,15 +25,11 @@ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; */ @Transient public class SimpleModificationTracker implements ModificationTracker { - static { - //noinspection ConstantConditions - assert Patches.JDK_BUG_ID_7103570; - } - private static final AtomicIntegerFieldUpdater UPDATER = AtomicIntegerFieldUpdater.newUpdater(SimpleModificationTracker.class, "myCounter"); - public volatile int myCounter; // is public to work around JDK-7103570 + @SuppressWarnings("unused") + private volatile int myCounter; @Override public long getModificationCount() { @@ -42,6 +37,10 @@ public class SimpleModificationTracker implements ModificationTracker { } public void incModificationCount() { - UPDATER.incrementAndGet(this); + incAndGetModificationCount(); + } + + public long incAndGetModificationCount() { + return UPDATER.incrementAndGet(this); } } \ No newline at end of file diff --git a/platform/core-api/src/com/intellij/openapi/vfs/DeprecatedVirtualFileSystem.java b/platform/core-api/src/com/intellij/openapi/vfs/DeprecatedVirtualFileSystem.java index d206dd51cf4a..f33c224d7b44 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/DeprecatedVirtualFileSystem.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/DeprecatedVirtualFileSystem.java @@ -49,7 +49,6 @@ public abstract class DeprecatedVirtualFileSystem extends VirtualFileSystem { myEventDispatcher.removeListener(listener); } - @SuppressWarnings("unused") protected void firePropertyChanged(Object requestor, @NotNull VirtualFile file, @NotNull String propertyName, @@ -60,42 +59,36 @@ public abstract class DeprecatedVirtualFileSystem extends VirtualFileSystem { myEventDispatcher.getMulticaster().propertyChanged(event); } - @SuppressWarnings("unused") protected void fireContentsChanged(Object requestor, @NotNull VirtualFile file, long oldModificationStamp) { assertWriteAccessAllowed(); VirtualFileEvent event = new VirtualFileEvent(requestor, file, file.getParent(), oldModificationStamp, file.getModificationStamp()); myEventDispatcher.getMulticaster().contentsChanged(event); } - @SuppressWarnings("unused") protected void fireFileCreated(@Nullable Object requestor, @NotNull VirtualFile file) { assertWriteAccessAllowed(); VirtualFileEvent event = new VirtualFileEvent(requestor, file, file.getName(), file.getParent()); myEventDispatcher.getMulticaster().fileCreated(event); } - @SuppressWarnings("unused") protected void fireFileDeleted(Object requestor, @NotNull VirtualFile file, @NotNull String fileName, VirtualFile parent) { assertWriteAccessAllowed(); VirtualFileEvent event = new VirtualFileEvent(requestor, file, fileName, parent); myEventDispatcher.getMulticaster().fileDeleted(event); } - @SuppressWarnings("unused") protected void fireFileMoved(Object requestor, @NotNull VirtualFile file, VirtualFile oldParent) { assertWriteAccessAllowed(); VirtualFileMoveEvent event = new VirtualFileMoveEvent(requestor, file, oldParent, file.getParent()); myEventDispatcher.getMulticaster().fileMoved(event); } - @SuppressWarnings("unused") protected void fireFileCopied(@Nullable Object requestor, @NotNull VirtualFile originalFile, @NotNull VirtualFile createdFile) { assertWriteAccessAllowed(); VirtualFileCopyEvent event = new VirtualFileCopyEvent(requestor, originalFile, createdFile); myEventDispatcher.getMulticaster().fileCopied(event); } - @SuppressWarnings("unused") protected void fireBeforePropertyChange(Object requestor, @NotNull VirtualFile file, @NotNull String propertyName, @@ -106,21 +99,18 @@ public abstract class DeprecatedVirtualFileSystem extends VirtualFileSystem { myEventDispatcher.getMulticaster().beforePropertyChange(event); } - @SuppressWarnings("unused") protected void fireBeforeContentsChange(Object requestor, @NotNull VirtualFile file) { assertWriteAccessAllowed(); VirtualFileEvent event = new VirtualFileEvent(requestor, file, file.getName(), file.getParent()); myEventDispatcher.getMulticaster().beforeContentsChange(event); } - @SuppressWarnings("unused") protected void fireBeforeFileDeletion(Object requestor, @NotNull VirtualFile file) { assertWriteAccessAllowed(); VirtualFileEvent event = new VirtualFileEvent(requestor, file, file.getName(), file.getParent()); myEventDispatcher.getMulticaster().beforeFileDeletion(event); } - @SuppressWarnings("unused") protected void fireBeforeFileMovement(Object requestor, @NotNull VirtualFile file, VirtualFile newParent) { assertWriteAccessAllowed(); VirtualFileMoveEvent event = new VirtualFileMoveEvent(requestor, file, file.getParent(), newParent); @@ -166,7 +156,7 @@ public abstract class DeprecatedVirtualFileSystem extends VirtualFileSystem { @NotNull @Override public VirtualFile copyFile(Object requestor, @NotNull VirtualFile vFile, @NotNull VirtualFile newParent, @NotNull String copyName) throws IOException { - throw unsupported("copyFile() not supported", vFile); + throw unsupported("copyFile", vFile); } private UnsupportedOperationException unsupported(String op, VirtualFile vFile) { diff --git a/platform/core-api/src/com/intellij/psi/CommonClassNames.java b/platform/core-api/src/com/intellij/psi/CommonClassNames.java index f2da8bc222e4..f1ff9187bee8 100644 --- a/platform/core-api/src/com/intellij/psi/CommonClassNames.java +++ b/platform/core-api/src/com/intellij/psi/CommonClassNames.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -105,6 +105,9 @@ public interface CommonClassNames { @NonNls String JAVA_UTIL_STREAM_BASE_STREAM = "java.util.stream.BaseStream"; @NonNls String JAVA_UTIL_STREAM_STREAM = "java.util.stream.Stream"; + @NonNls String JAVA_UTIL_STREAM_INT_STREAM = "java.util.stream.IntStream"; + @NonNls String JAVA_UTIL_STREAM_LONG_STREAM = "java.util.stream.LongStream"; + @NonNls String JAVA_UTIL_STREAM_DOUBLE_STREAM = "java.util.stream.DoubleStream"; @NonNls String JAVA_UTIL_STREAM_COLLECTORS = "java.util.stream.Collectors"; @NonNls String JAVA_UTIL_FUNCTION_PREDICATE = "java.util.function.Predicate"; diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java index 3233e3359ea3..1ce0f42443a5 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java @@ -15,6 +15,8 @@ */ package com.intellij.openapi.editor.impl; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.ex.MarkupIterator; import com.intellij.openapi.util.Getter; import com.intellij.util.IncorrectOperationException; @@ -42,6 +44,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * User: cdr */ abstract class IntervalTreeImpl extends RedBlackTree implements IntervalTree { + static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.RangeMarkerTree"); + static final boolean DEBUG = LOG.isDebugEnabled() || ApplicationManager.getApplication() != null && (ApplicationManager.getApplication().isUnitTestMode() || ApplicationManager.getApplication().isInternal()); private int keySize; // number of all intervals, counting all duplicates, some of them maybe gced final ReadWriteLock l = new ReentrantReadWriteLock(); @@ -66,7 +70,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< @NotNull private final IntervalTreeImpl myIntervalTree; - public IntervalNode(@NotNull IntervalTreeImpl intervalTree, @NotNull E key, int start, int end) { + IntervalNode(@NotNull IntervalTreeImpl intervalTree, @NotNull E key, int start, int end) { // maxEnd == 0 so to not disrupt existing maxes myIntervalTree = intervalTree; myStart = start; @@ -374,7 +378,9 @@ abstract class IntervalTreeImpl extends RedBlackTree< } private void assertUnderWriteLock() { - assert isAcquired(l.writeLock()) : l.writeLock(); + if (DEBUG) { + assert isAcquired(l.writeLock()) : l.writeLock(); + } } private static boolean isAcquired(@NotNull Lock l) { String s = l.toString(); diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java index 14ef8ccc977e..e012f11af497 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java @@ -17,7 +17,6 @@ package com.intellij.openapi.editor.impl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.impl.ApplicationInfoImpl; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.ex.PrioritizedDocumentListener; @@ -38,9 +37,6 @@ import java.util.concurrent.atomic.AtomicInteger; * User: cdr */ public class RangeMarkerTree extends IntervalTreeImpl { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.RangeMarkerTree"); - private static final boolean DEBUG = LOG.isDebugEnabled() || ApplicationManager.getApplication() != null && (ApplicationManager.getApplication().isUnitTestMode() || ApplicationManager.getApplication().isInternal()); - private final PrioritizedDocumentListener myListener; private final Document myDocument; @@ -159,12 +155,12 @@ public class RangeMarkerTree extends IntervalTreeImpl rangeMarkerTree, - @NotNull T key, - int start, - int end, - boolean greedyToLeft, - boolean greedyToRight) { + RMNode(@NotNull RangeMarkerTree rangeMarkerTree, + @NotNull T key, + int start, + int end, + boolean greedyToLeft, + boolean greedyToRight) { super(rangeMarkerTree, key, start, end); setFlag(EXPAND_TO_LEFT_FLAG, greedyToLeft); setFlag(EXPAND_TO_RIGHT_FLAG, greedyToRight); diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonMergeUtil.java b/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonMergeUtil.java index 1b1b926d6f9d..7c8340f04f45 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonMergeUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonMergeUtil.java @@ -20,6 +20,7 @@ import com.intellij.diff.util.MergeRange; import com.intellij.diff.util.Range; import com.intellij.diff.util.Side; import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.util.registry.Registry; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -160,6 +161,11 @@ public class ComparisonMergeUtil { public static CharSequence tryResolveConflict(@NotNull CharSequence leftText, @NotNull CharSequence baseText, @NotNull CharSequence rightText) { - return MergeResolveUtil.tryResolveConflict(leftText, baseText, rightText); + if (Registry.is("diff.merge.resolve.conflict.action.use.greedy.approach")) { + return MergeResolveUtil.tryGreedyResolve(leftText, baseText, rightText); + } + else { + return MergeResolveUtil.tryResolve(leftText, baseText, rightText); + } } } \ No newline at end of file diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/MergeResolveUtil.kt b/platform/diff-impl/src/com/intellij/diff/comparison/MergeResolveUtil.kt index 4096c79fc003..df886328b8e6 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/MergeResolveUtil.kt +++ b/platform/diff-impl/src/com/intellij/diff/comparison/MergeResolveUtil.kt @@ -16,13 +16,29 @@ package com.intellij.diff.comparison import com.intellij.diff.fragments.DiffFragment +import com.intellij.diff.util.DiffUtil import com.intellij.diff.util.Side import com.intellij.diff.util.Side.LEFT import com.intellij.diff.util.Side.RIGHT +import com.intellij.diff.util.TextDiffType +import com.intellij.diff.util.ThreeSide import com.intellij.openapi.progress.DumbProgressIndicator import com.intellij.util.text.MergingCharSequence object MergeResolveUtil { + @JvmStatic + fun tryResolve(leftText: CharSequence, baseText: CharSequence, rightText: CharSequence): CharSequence? { + try { + val resolved = tryResolve(leftText, baseText, rightText, ComparisonPolicy.DEFAULT) + if (resolved != null) return resolved + + return tryResolve(leftText, baseText, rightText, ComparisonPolicy.IGNORE_WHITESPACES) + } + catch (e: DiffTooBigException) { + return null + } + } + /* * Here we assume, that resolve results are explicitly verified by user and can be safely undone. * Thus we trade higher chances of incorrect resolve for higher chances of correct resolve. @@ -36,12 +52,12 @@ object MergeResolveUtil { * modifications can be considered as "insertion + deletion" and resolved accordingly. */ @JvmStatic - fun tryResolveConflict(leftText: CharSequence, baseText: CharSequence, rightText: CharSequence): CharSequence? { + fun tryGreedyResolve(leftText: CharSequence, baseText: CharSequence, rightText: CharSequence): CharSequence? { try { - val resolved = Helper(leftText, baseText, rightText).execute(ComparisonPolicy.DEFAULT) + val resolved = tryGreedyResolve(leftText, baseText, rightText, ComparisonPolicy.DEFAULT) if (resolved != null) return resolved - return Helper(leftText, baseText, rightText).execute(ComparisonPolicy.IGNORE_WHITESPACES) + return tryGreedyResolve(leftText, baseText, rightText, ComparisonPolicy.IGNORE_WHITESPACES) } catch (e: DiffTooBigException) { return null @@ -49,6 +65,46 @@ object MergeResolveUtil { } } +private fun tryResolve(leftText: CharSequence, baseText: CharSequence, rightText: CharSequence, + policy: ComparisonPolicy): CharSequence? { + val texts = listOf(leftText, baseText, rightText) + + val changes = ByWord.compare(leftText, baseText, rightText, policy, DumbProgressIndicator.INSTANCE) + + val newContent = StringBuilder() + + var last = 0 + for (fragment in changes) { + val type = DiffUtil.getWordMergeType(fragment, texts, policy) + if (type.diffType == TextDiffType.CONFLICT) return null; + + val baseStart = fragment.getStartOffset(ThreeSide.BASE) + val baseEnd = fragment.getEndOffset(ThreeSide.BASE) + + newContent.append(baseText, last, baseStart) + + if (type.isChange(Side.LEFT)) { + val leftStart = fragment.getStartOffset(ThreeSide.LEFT) + val leftEnd = fragment.getEndOffset(ThreeSide.LEFT) + newContent.append(leftText, leftStart, leftEnd) + } + else { + val rightStart = fragment.getStartOffset(ThreeSide.RIGHT) + val rightEnd = fragment.getEndOffset(ThreeSide.RIGHT) + newContent.append(rightText, rightStart, rightEnd) + } + last = baseEnd + } + + newContent.append(baseText, last, baseText.length) + return newContent.toString() +} + +private fun tryGreedyResolve(leftText: CharSequence, baseText: CharSequence, rightText: CharSequence, + policy: ComparisonPolicy): CharSequence? { + return Helper(leftText, baseText, rightText).execute(policy) +} + private class Helper(val leftText: CharSequence, val baseText: CharSequence, val rightText: CharSequence) { val newContent = StringBuilder() diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java index fc8d62f14922..3ade1e10cfd3 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java @@ -23,6 +23,7 @@ import com.intellij.diff.SuppressiveDiffTool; import com.intellij.diff.comparison.ByWord; import com.intellij.diff.comparison.ComparisonManager; import com.intellij.diff.comparison.ComparisonPolicy; +import com.intellij.diff.comparison.ComparisonUtil; import com.intellij.diff.contents.DiffContent; import com.intellij.diff.contents.DocumentContent; import com.intellij.diff.contents.EmptyContent; @@ -30,6 +31,7 @@ import com.intellij.diff.contents.FileContent; import com.intellij.diff.fragments.DiffFragment; import com.intellij.diff.fragments.LineFragment; import com.intellij.diff.fragments.MergeLineFragment; +import com.intellij.diff.fragments.MergeWordFragment; import com.intellij.diff.impl.DiffSettingsHolder; import com.intellij.diff.impl.DiffSettingsHolder.DiffSettings; import com.intellij.diff.requests.ContentDiffRequest; @@ -1069,6 +1071,36 @@ public class DiffUtil { return fragment.getStartLine(side) == fragment.getEndLine(side); } + @NotNull + public static MergeConflictType getWordMergeType(@NotNull MergeWordFragment fragment, + @NotNull List texts, + @NotNull ComparisonPolicy policy) { + return getMergeType((side) -> isWordMergeIntervalEmpty(fragment, side), + (side1, side2) -> compareWordMergeContents(fragment, texts, policy, side1, side2)); + } + + private static boolean compareWordMergeContents(@NotNull MergeWordFragment fragment, + @NotNull List texts, + @NotNull ComparisonPolicy policy, + @NotNull ThreeSide side1, + @NotNull ThreeSide side2) { + int start1 = fragment.getStartOffset(side1); + int end1 = fragment.getEndOffset(side1); + int start2 = fragment.getStartOffset(side2); + int end2 = fragment.getEndOffset(side2); + + CharSequence document1 = side1.select(texts); + CharSequence document2 = side2.select(texts); + + CharSequence content1 = document1.subSequence(start1, end1); + CharSequence content2 = document2.subSequence(start2, end2); + return ComparisonUtil.isEquals(content1, content2, policy); + } + + private static boolean isWordMergeIntervalEmpty(@NotNull MergeWordFragment fragment, @NotNull ThreeSide side) { + return fragment.getStartOffset(side) == fragment.getEndOffset(side); + } + // // Writable // diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/MergeResolveUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/MergeResolveUtilTest.kt index 1283f7ed8f46..c5c299bd593a 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/MergeResolveUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/MergeResolveUtilTest.kt @@ -118,35 +118,35 @@ class MergeResolveUtilTest : DiffTestCase() { } fun testNonFailureConflicts() { - test( + testGreedy( "x X x", "x x", "x X Y x", "x Y x" ) - test( + testGreedy( "x X x", "x x", "x Y X x", "x Y x" ) - test( + testGreedy( "x X Y x", "x X x", "x Y x", "x x" ) - test( + testGreedy( "x X Y Z x", "x X x", "x Z x", "x x" ) - test( + testGreedy( "x A B C D E F G H K x", "x C F K x", "x A D H x", @@ -157,21 +157,21 @@ class MergeResolveUtilTest : DiffTestCase() { fun testConfusingConflicts() { // these cases might be a failure as well - test( + testGreedy( "x X x", "x x", "x Z x", "xZ x" ) - test( + testGreedy( "x X X x", "x X Y X x", "x x", "x Y x" ) - test( + testGreedy( "x X x", "x x", "x Y x", @@ -179,7 +179,7 @@ class MergeResolveUtilTest : DiffTestCase() { ) - test( + testGreedy( "x X X x", "x Y x", "x X Y x", @@ -187,8 +187,25 @@ class MergeResolveUtilTest : DiffTestCase() { ) } - private fun test(base: String, left: String, right: String, expected: String?) { - val actual = MergeResolveUtil.tryResolveConflict(left, base, right) - assertEquals(expected, actual?.toString()) + private fun testGreedy(base: String, left: String, right: String, expected: String?) { + test(base, left, right, expected, true); + } + + private fun test(base: String, left: String, right: String, expected: String?, isGreedy: Boolean = false) { + val simpleResult = MergeResolveUtil.tryResolve(left, base, right) + val magicResult = MergeResolveUtil.tryGreedyResolve(left, base, right); + + if (expected == null) { + assertNull(simpleResult) + assertNull(magicResult) + } + else if (isGreedy) { + assertNull(simpleResult) + assertEquals(expected, magicResult) + } + else { + assertEquals(expected, simpleResult) + assertEquals(expected, magicResult) + } } } diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java index 95321651f571..c0c7055eddf6 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java @@ -173,8 +173,7 @@ public class UISettings extends SimpleModificationTracker implements PersistentS ColorBlindnessSupport support = ColorBlindnessSupport.get(COLOR_BLINDNESS); IconLoader.setFilter(support == null ? null : support.getFilter()); - incModificationCount(); - if (myCounter == 1) { + if (incAndGetModificationCount() == 1) { return; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hints/PopupActions.kt b/platform/lang-impl/src/com/intellij/codeInsight/hints/PopupActions.kt index b6e8057b2f99..e28ed40babb7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hints/PopupActions.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/hints/PopupActions.kt @@ -27,6 +27,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.editor.Editor 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 @@ -116,7 +117,7 @@ class ToggleInlineHintsAction : AnAction() { private fun hasParameterHintAtOffset(editor: Editor): Boolean { val offset = editor.caretModel.offset - return editor.inlayModel + return editor.inlayModel is InlayModelImpl && editor.inlayModel .getInlineElementsInRange(offset, offset) .find { ParameterHintsPresentationManager.getInstance().isParameterHint(it) } != null } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/ApplicationInspectionProfileManager.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/ApplicationInspectionProfileManager.java index 93ec446cb6f5..cdb88bebf4aa 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/ApplicationInspectionProfileManager.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/ApplicationInspectionProfileManager.java @@ -22,7 +22,6 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInsight.daemon.impl.SeveritiesProvider; import com.intellij.codeInsight.daemon.impl.SeverityRegistrar; import com.intellij.codeInsight.daemon.impl.analysis.HighlightingSettingsPerFile; -import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.configurationStore.BundledSchemeEP; import com.intellij.configurationStore.SchemeDataHolder; @@ -61,8 +60,6 @@ import java.util.Collections; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; -import static com.intellij.codeInspection.ex.InspectionProfileImpl.getDefaultProfile; - @State( name = "InspectionProfileManager", storages = { @@ -93,8 +90,8 @@ public class ApplicationInspectionProfileManager extends BaseInspectionProfileMa mySchemeManager = schemeManagerFactory.create(INSPECTION_DIR, new InspectionProfileProcessor() { @NotNull @Override - public String getName(@NotNull Function attributeProvider) { - return "unnamed"; + public String getName(@NotNull Function attributeProvider, @NotNull String fileNameWithoutExtension) { + return fileNameWithoutExtension; } @NotNull @@ -102,11 +99,7 @@ public class ApplicationInspectionProfileManager extends BaseInspectionProfileMa @NotNull String name, @NotNull Function attributeProvider, boolean isBundled) { - InspectionProfileImpl profile = new InspectionProfileImpl(name, myRegistrar, ApplicationInspectionProfileManager.this, dataHolder); - if (isBundled) { - profile.lockProfile(true); - } - return profile; + return new InspectionProfileImpl(name, myRegistrar, ApplicationInspectionProfileManager.this, dataHolder); } @Override @@ -169,21 +162,15 @@ public class ApplicationInspectionProfileManager extends BaseInspectionProfileMa } public void initProfiles() { - if (!myProfilesAreInitialized.compareAndSet(false, true)) { + if (!myProfilesAreInitialized.compareAndSet(false, true) || !LOAD_PROFILES) { return; } - if (!LOAD_PROFILES) return; - loadBundledSchemes(); mySchemeManager.loadSchemes(); - createDefaultProfile(); - } - private void createDefaultProfile() { - final InspectionProfileImpl oldDefault = mySchemeManager.findSchemeByName(InspectionProfileImpl.DEFAULT_PROFILE_NAME); - if (oldDefault == null || !oldDefault.isProfileLocked()) { - getSchemeManager().addScheme(createSampleProfile(InspectionProfileImpl.DEFAULT_PROFILE_NAME, getDefaultProfile())); + if (mySchemeManager.isEmpty()) { + mySchemeManager.addScheme(createSampleProfile(InspectionProfileImpl.DEFAULT_PROFILE_NAME, InspectionProfileImpl.getBaseProfile())); } } @@ -246,12 +233,6 @@ public class ApplicationInspectionProfileManager extends BaseInspectionProfileMa return new InspectionProfileConvertor(this); } - @SuppressWarnings("unused") - @Deprecated - public InspectionProfileImpl createProfile() { - return createSampleProfile(InspectionProfileImpl.DEFAULT_PROFILE_NAME, getDefaultProfile()); - } - @Override public void setRootProfile(@Nullable String profileName) { mySchemeManager.setCurrentSchemeName(profileName); @@ -270,12 +251,12 @@ public class ApplicationInspectionProfileManager extends BaseInspectionProfileMa @NotNull @Override - public InspectionProfile getCurrentProfile() { + public InspectionProfileImpl getCurrentProfile() { initProfiles(); - Profile current = mySchemeManager.getCurrentScheme(); + InspectionProfileImpl current = mySchemeManager.getCurrentScheme(); if (current != null) { - return (InspectionProfile)current; + return current; } // use default as base, not random custom profile diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java index a9e9a497add1..00e499a60699 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java @@ -289,7 +289,10 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb public boolean isExcludedOrUnderExcludedDirectory(@NotNull VirtualFile file) { ModifiableRootModel model = getModel(); - Project project = model != null ? model.getProject() : null; + if (model == null) { + throw new AssertionError(getClass() + ".getModel() returned null unexpectedly"); + } + Project project = model.getProject(); ContentEntry contentEntry = getContentEntry(); if (contentEntry == null) { return false; diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java index e2c8abe2e6c3..b28890076aa8 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java @@ -74,7 +74,6 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.FocusManager; import javax.swing.*; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; @@ -84,8 +83,6 @@ import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import java.awt.*; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import java.io.IOException; import java.io.StringReader; import java.util.*; @@ -1095,6 +1092,7 @@ public class SingleInspectionProfilePanel extends JPanel { } public boolean isModified() { + if (myTreeTable == null) return false; if (myModified) return true; if (myProfile.isChanged()) return true; if (myProfile.getParentProfile().isProjectLevel() != myProfile.isProjectLevel()) return true; diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java index fc8ff4abd3e9..9da66f7a13d8 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java @@ -108,7 +108,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable } @NotNull - private InspectionProfileImpl copyToNewProfile(ModifiableModel selectedProfile, + private InspectionProfileImpl copyToNewProfile(@NotNull InspectionProfileImpl selectedProfile, @NotNull Project project, boolean modifyName, boolean modifyLevel) { diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureProcessorBase.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureProcessorBase.java index b61abc436e2c..9cfba7716f3e 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureProcessorBase.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureProcessorBase.java @@ -93,7 +93,10 @@ public abstract class ChangeSignatureProcessorBase extends BaseRefactoringProces List infos = new ArrayList<>(); final ChangeSignatureUsageProcessor[] processors = ChangeSignatureUsageProcessor.EP_NAME.getExtensions(); for (ChangeSignatureUsageProcessor processor : processors) { - ContainerUtil.addAll(infos, processor.findUsages(changeInfo)); + for (UsageInfo info : processor.findUsages(changeInfo)) { + LOG.assertTrue(info != null, processor); + infos.add(info); + } } infos = filterUsages(infos); return infos.toArray(new UsageInfo[infos.size()]); diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java index 3cd1af45f6b3..f2b15f2d94eb 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java @@ -36,6 +36,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.util.PsiUtilCore; @@ -101,7 +102,7 @@ public class VariableInplaceRenamer extends InplaceRefactoring { protected void collectAdditionalElementsToRename(final List> stringUsages) { final String stringToSearch = myElementToRename.getName(); final PsiFile currentFile = PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument()); - if (stringToSearch != null) { + if (!StringUtil.isEmptyOrSpaces(stringToSearch)) { TextOccurrencesUtil .processUsagesInStringsAndComments(myElementToRename, stringToSearch, true, (psiElement, textRange) -> { if (psiElement.getContainingFile() == currentFile) { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerMap.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerMap.java index 7350f2bc7d80..e6789513ee35 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerMap.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerMap.java @@ -15,9 +15,7 @@ */ package com.intellij.util.indexing; -import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; import com.intellij.util.io.DataExternalizer; -import com.intellij.util.io.DataOutputStream; import com.intellij.util.io.KeyDescriptor; import com.intellij.util.io.PersistentHashMap; import org.jetbrains.annotations.NotNull; @@ -56,15 +54,10 @@ class ValueContainerMap extends PersistentHashMap ourCurrentEventDispatchContext = new ThreadLocal<>(); - private static class VfsEventDispatchContext { + private static class VfsEventDispatchContext implements AutoCloseable { final List myEvents; final boolean myBeforeEvents; final VfsEventDispatchContext myPreviousContext; VersionedFilterData myFilterData; - VfsEventDispatchContext(List events, boolean beforeEvents, VfsEventDispatchContext context) { + VfsEventDispatchContext(List events, boolean beforeEvents) { myEvents = events; myBeforeEvents = beforeEvents; - myPreviousContext = context; + myPreviousContext = ourCurrentEventDispatchContext.get(); + if (myPreviousContext != null) { + myFilterData = myPreviousContext.myFilterData; + } + ourCurrentEventDispatchContext.set(this); } public void close() { ourCurrentEventDispatchContext.set(myPreviousContext); + if (myPreviousContext != null && myPreviousContext.myFilterData == null && myFilterData != null) { + myPreviousContext.myFilterData = myFilterData; + } } } public void runWithVfsEventsDispatchContext(List events, boolean beforeEvents, Runnable action) { - VfsEventDispatchContext vfsEventDispatchContext = new VfsEventDispatchContext(events, beforeEvents, ourCurrentEventDispatchContext.get()); - ourCurrentEventDispatchContext.set(vfsEventDispatchContext); - try { + try (VfsEventDispatchContext ignored = new VfsEventDispatchContext(events, beforeEvents)) { action.run(); - } finally { - vfsEventDispatchContext.close(); } } diff --git a/platform/platform-api/src/com/intellij/credentialStore/CredentialAttributes.kt b/platform/platform-api/src/com/intellij/credentialStore/CredentialAttributes.kt index 4498a7ea53c7..c156af30d340 100644 --- a/platform/platform-api/src/com/intellij/credentialStore/CredentialAttributes.kt +++ b/platform/platform-api/src/com/intellij/credentialStore/CredentialAttributes.kt @@ -62,7 +62,7 @@ fun CredentialAttributes(requestor: Class<*>, userName: String?) = CredentialAtt fun Credentials?.isFulfilled() = this != null && userName != null && !password.isNullOrEmpty() fun Credentials?.hasOnlyUserName() = this != null && userName != null && password.isNullOrEmpty() -fun Credentials?.isEmpty() = this == null || (userName == null && password == null) +fun Credentials?.isEmpty() = this == null || (userName == null && password.isNullOrEmpty()) // input will be cleared @JvmOverloads diff --git a/platform/platform-api/src/com/intellij/openapi/MnemonicWrapper.java b/platform/platform-api/src/com/intellij/openapi/MnemonicWrapper.java index 2c78265d1726..e1bb409c0904 100644 --- a/platform/platform-api/src/com/intellij/openapi/MnemonicWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/MnemonicWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,19 +15,17 @@ */ package com.intellij.openapi; -import com.intellij.Patches; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; import com.intellij.util.ui.UIUtil; import javax.swing.*; -import java.awt.Component; +import java.awt.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.lang.reflect.Method; /** * @author Sergey.Malenkov @@ -136,7 +134,7 @@ abstract class MnemonicWrapper implements Runnable, Propert sb.append(ch); } else if (i + 1 < length) { - code = getExtendedKeyCodeForChar(text.charAt(i + 1)); + code = KeyEvent.getExtendedKeyCodeForChar((int)text.charAt(i + 1)); index = sb.length(); } } @@ -200,26 +198,6 @@ abstract class MnemonicWrapper implements Runnable, Propert return stroke; } - // TODO: HACK because of Java7 required: - // replace later with KeyEvent.getExtendedKeyCodeForChar(ch) - private static int getExtendedKeyCodeForChar(int ch) { - //noinspection ConstantConditions - assert Patches.USE_REFLECTION_TO_ACCESS_JDK7; - try { - Method method = KeyEvent.class.getMethod("getExtendedKeyCodeForChar", int.class); - if (!method.isAccessible()) { - method.setAccessible(true); - } - return (Integer)method.invoke(KeyEvent.class, ch); - } - catch (Exception exception) { - if (ch >= 'a' && ch <= 'z') { - ch -= ('a' - 'A'); - } - return ch; - } - } - private static class MenuWrapper extends ButtonWrapper { private MenuWrapper(AbstractButton component) { super(component); diff --git a/platform/platform-api/src/com/intellij/openapi/fileTypes/FileTypeManager.java b/platform/platform-api/src/com/intellij/openapi/fileTypes/FileTypeManager.java index ecc24a8a5579..0791b837820e 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileTypes/FileTypeManager.java +++ b/platform/platform-api/src/com/intellij/openapi/fileTypes/FileTypeManager.java @@ -19,7 +19,6 @@ import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.CachedSingletonsRegistry; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Getter; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.messages.Topic; import org.jetbrains.annotations.NonNls; @@ -36,7 +35,7 @@ import java.util.List; public abstract class FileTypeManager extends FileTypeRegistry { static { - FileTypeRegistry.ourInstanceGetter = () -> FileTypeManager.getInstance(); + FileTypeRegistry.ourInstanceGetter = () -> getInstance(); } private static FileTypeManager ourInstance = CachedSingletonsRegistry.markCachedField(FileTypeManager.class); @@ -59,7 +58,7 @@ public abstract class FileTypeManager extends FileTypeRegistry { } /** - * @deprecated use {@link com.intellij.openapi.fileTypes.FileTypeFactory} instead + * @deprecated use {@link FileTypeFactory} instead */ public abstract void registerFileType(@NotNull FileType type, @NotNull List defaultAssociations); @@ -69,7 +68,7 @@ public abstract class FileTypeManager extends FileTypeRegistry { * @param type The file type to register. * @param defaultAssociatedExtensions The list of extensions which cause the file to be * treated as the specified file type. The extensions should not start with '.'. - * @deprecated use {@link com.intellij.openapi.fileTypes.FileTypeFactory} instead + * @deprecated use {@link FileTypeFactory} instead */ public final void registerFileType(@NotNull FileType type, @NonNls @Nullable String... defaultAssociatedExtensions) { List matchers = new ArrayList<>(); diff --git a/platform/platform-api/src/com/intellij/ui/content/ContentManager.java b/platform/platform-api/src/com/intellij/ui/content/ContentManager.java index 4a6dcbcf1e8e..08386ba6c5b6 100644 --- a/platform/platform-api/src/com/intellij/ui/content/ContentManager.java +++ b/platform/platform-api/src/com/intellij/ui/content/ContentManager.java @@ -34,6 +34,10 @@ public interface ContentManager extends Disposable, BusyObject { void addContent(@NotNull Content content); void addContent(@NotNull Content content, final int order); + + /** + * @deprecated use {@link #addContent(Content)} instead, {@code constraints} parameter isn't used anyway + */ void addContent(@NotNull Content content, Object constraints); boolean removeContent(@NotNull Content content, final boolean dispose); diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java index 48c1678bd249..6aab28aa8d20 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 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. @@ -34,7 +34,7 @@ import java.awt.*; import java.awt.event.MouseListener; public class HintUtil { - public static final Color INFORMATION_COLOR = new JBColor(new Color(253, 254, 226), new Color(0x4d4f51)); + public static final Color INFORMATION_COLOR = new JBColor(new Color(0xf8f8f8), new Color(0x4d4f51)); public static final Color QUESTION_COLOR = new JBColor(new Color(181, 208, 251), new Color(55, 108, 137)); public static final Color ERROR_COLOR = new JBColor(new Color(255, 220, 220), new Color(0x781732)); diff --git a/platform/platform-impl/src/com/intellij/diagnostic/JetBrainsAccountDialog.kt b/platform/platform-impl/src/com/intellij/diagnostic/JetBrainsAccountDialog.kt index 99dbed90dab6..cc009b7cd6f6 100644 --- a/platform/platform-impl/src/com/intellij/diagnostic/JetBrainsAccountDialog.kt +++ b/platform/platform-impl/src/com/intellij/diagnostic/JetBrainsAccountDialog.kt @@ -49,7 +49,7 @@ fun showJetBrainsAccountDialog(parent: Component, project: Project? = null): Dia link("Forgot password?") { BrowserUtil.browse("https://account.jetbrains.com/forgot-password?username=${userField.text.trim().encodeUrlQueryParameter()}") } } } - noteRow("""Do not have an account? Sign Up""") + noteRow("""Do not have an account? Sign Up""") } return dialog( diff --git a/platform/platform-impl/src/com/intellij/ide/dnd/TransferableList.java b/platform/platform-impl/src/com/intellij/ide/dnd/TransferableList.java index 1de9a4377ef7..e79b3f4469ca 100644 --- a/platform/platform-impl/src/com/intellij/ide/dnd/TransferableList.java +++ b/platform/platform-impl/src/com/intellij/ide/dnd/TransferableList.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ */ package com.intellij.ide.dnd; -import com.intellij.Patches; import org.jetbrains.annotations.NotNull; import java.awt.datatransfer.DataFlavor; @@ -31,20 +30,8 @@ import java.util.List; */ abstract public class TransferableList implements Transferable { private static final DataFlavor LIST_DATA_FLAVOR = new DataFlavor(List.class, "Transferable List"); - private static final DataFlavor ALL_HTML_DATA_FLAVOR = initHtmlDataFlavor("all"); // JDK7: DataFlavor.allHtmlFlavor - private static final DataFlavor PART_HTML_DATA_FLAVOR = initHtmlDataFlavor("fragment"); // JDK7: DataFlavor.fragmentHtmlFlavor - - private static DataFlavor initHtmlDataFlavor(String type) { - // some constants were added in JDK 7 without @since 1.7 tag - // http://bugs.openjdk.java.net/browse/JDK-7075105 - assert Patches.USE_REFLECTION_TO_ACCESS_JDK7; - try { - return new DataFlavor("text/html; class=java.lang.String;document=" + type + ";charset=Unicode"); - } - catch (Exception exception) { - return null; - } - } + private static final DataFlavor ALL_HTML_DATA_FLAVOR = DataFlavor.allHtmlFlavor; + private static final DataFlavor PART_HTML_DATA_FLAVOR = DataFlavor.fragmentHtmlFlavor; private final List myList; diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.java index d7f172573af4..fc506a13dbe4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenu.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,7 @@ import com.intellij.ui.plaf.beg.IdeaMenuUI; import com.intellij.ui.plaf.gtk.GtkMenuUI; import com.intellij.util.ReflectionUtil; import com.intellij.util.SingleAlarm; +import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -40,6 +41,7 @@ import javax.swing.*; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import javax.swing.plaf.MenuItemUI; +import javax.swing.plaf.synth.SynthMenuUI; import java.awt.*; import java.awt.event.AWTEventListener; import java.awt.event.ComponentEvent; @@ -164,12 +166,12 @@ public final class ActionMenu extends JBMenu { if (myTopLevel && UIUtil.isUnderGTKLookAndFeel()) { Insets insets = getInsets(); - Insets newInsets = new Insets(insets.top, insets.left, insets.bottom, insets.right); - if (insets.top + insets.bottom < 6) { - newInsets.top = newInsets.bottom = 3; + @SuppressWarnings("UseDPIAwareInsets") Insets newInsets = new Insets(insets.top, insets.left, insets.bottom, insets.right); + if (insets.top + insets.bottom < JBUI.scale(6)) { + newInsets.top = newInsets.bottom = JBUI.scale(3); } - if (insets.left + insets.right < 12) { - newInsets.left = newInsets.right = 6; + if (insets.left + insets.right < JBUI.scale(12)) { + newInsets.left = newInsets.right = JBUI.scale(6); } if (!newInsets.equals(insets)) { setBorder(BorderFactory.createEmptyBorder(newInsets.top, newInsets.left, newInsets.bottom, newInsets.right)); @@ -178,8 +180,8 @@ public final class ActionMenu extends JBMenu { } @Override - public void setUI(final MenuItemUI ui) { - final MenuItemUI newUi = !myTopLevel && UIUtil.isUnderGTKLookAndFeel() && GtkMenuUI.isUiAcceptable(ui) ? new GtkMenuUI(ui) : ui; + public void setUI(MenuItemUI ui) { + MenuItemUI newUi = !myTopLevel && UIUtil.isUnderGTKLookAndFeel() && ui instanceof SynthMenuUI ? new GtkMenuUI((SynthMenuUI)ui) : ui; super.setUI(newUi); } @@ -222,7 +224,8 @@ public final class ActionMenu extends JBMenu { } private void updateIcon() { - if (UISettings.getInstance().SHOW_ICONS_IN_MENUS) { + UISettings settings = UISettings.getInstance(); + if (settings != null && settings.SHOW_ICONS_IN_MENUS) { final Presentation presentation = myPresentation; final Icon icon = presentation.getIcon(); setIcon(icon); @@ -242,9 +245,7 @@ public final class ActionMenu extends JBMenu { } public static void showDescriptionInStatusBar(boolean isIncluded, Component component, String description) { - IdeFrame frame = component instanceof IdeFrame - ? (IdeFrame)component - : (IdeFrame)SwingUtilities.getAncestorOfClass(IdeFrame.class, component); + IdeFrame frame = (IdeFrame)(component instanceof IdeFrame ? component : SwingUtilities.getAncestorOfClass(IdeFrame.class, component)); StatusBar statusBar; if (frame != null && (statusBar = frame.getStatusBar()) != null) { statusBar.setInfo(isIncluded ? description : null); @@ -448,4 +449,4 @@ public final class ActionMenu extends JBMenu { Toolkit.getDefaultToolkit().removeAWTEventListener(this); } } -} +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenuItem.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenuItem.java index d3fb034d8f16..a50afb68e1b2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenuItem.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionMenuItem.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,7 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.plaf.MenuItemUI; +import javax.swing.plaf.synth.SynthMenuItemUI; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -187,8 +188,8 @@ public class ActionMenuItem extends JBCheckBoxMenuItem { } @Override - public void setUI(final MenuItemUI ui) { - final MenuItemUI newUi = UIUtil.isUnderGTKLookAndFeel() && GtkMenuItemUI.isUiAcceptable(ui) ? new GtkMenuItemUI(ui) : ui; + public void setUI(MenuItemUI ui) { + MenuItemUI newUi = UIUtil.isUnderGTKLookAndFeel() && ui instanceof SynthMenuItemUI ? new GtkMenuItemUI((SynthMenuItemUI)ui) : ui; super.setUI(newUi); } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java index 92e3b69e2a0e..609204ff1942 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java @@ -30,6 +30,7 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.psi.PsiDocumentManager; +import com.intellij.ui.EditorNotifications; import com.intellij.util.concurrency.AppExecutorUtil; import org.jetbrains.annotations.NotNull; @@ -172,6 +173,7 @@ public class AsyncEditorLoader { if (FileEditorManager.getInstance(myProject).getSelectedTextEditor() == myEditor) { IdeFocusManager.getInstance(myProject).requestFocus(myTextEditor.getPreferredFocusedComponent(), true); } + EditorNotifications.getInstance(myProject).updateNotifications(myTextEditor.myFile); } public static void performWhenLoaded(@NotNull Editor editor, @NotNull Runnable runnable) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/StripeButtonUI.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/StripeButtonUI.java index 2c8022e7b864..69766e3b0192 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/StripeButtonUI.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/StripeButtonUI.java @@ -37,11 +37,12 @@ public final class StripeButtonUI extends MetalToggleButtonUI{ private static final Rectangle ourIconRect=new Rectangle(); private static final Rectangle ourTextRect=new Rectangle(); private static final Rectangle ourViewRect=new Rectangle(); - private static Insets ourViewInsets=new Insets(0,0,0,0); + private static Insets ourViewInsets = JBUI.emptyInsets(); private StripeButtonUI(){} /** Invoked by reflection */ + @SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass", "unused"}) public static ComponentUI createUI(final JComponent c){ return ourInstance; } @@ -55,6 +56,7 @@ public final class StripeButtonUI extends MetalToggleButtonUI{ final ToolWindowAnchor anchor=button.getAnchor(); if(ToolWindowAnchor.LEFT==anchor||ToolWindowAnchor.RIGHT==anchor){ + //noinspection SuspiciousNameCombination return new Dimension(dim.height,dim.width); } else{ return dim; @@ -127,12 +129,14 @@ public final class StripeButtonUI extends MetalToggleButtonUI{ tr=g2.getTransform(); if(ToolWindowAnchor.RIGHT==anchor){ if(icon != null){ // do not rotate icon + //noinspection SuspiciousNameCombination icon.paintIcon(c, g2, ourIconRect.y, ourIconRect.x); } g2.rotate(Math.PI/2); g2.translate(0,-c.getWidth()); } else { if(icon != null){ // do not rotate icon + //noinspection SuspiciousNameCombination icon.paintIcon(c, g2, ourIconRect.y, c.getHeight() - ourIconRect.x - icon.getIconHeight()); } g2.rotate(-Math.PI/2); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index 5670ecc8410b..2ef6de9cbb90 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -451,13 +451,12 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements toolWindow.setSplitMode(true, null); } - final ActionCallback activation = toolWindow.setActivation(new ActionCallback()); - + // ToolWindow activation is not needed anymore and should be removed in 2017 + toolWindow.setActivation(new ActionCallback()).setDone(); final DumbAwareRunnable runnable = () -> { if (toolWindow.isDisposed()) return; toolWindow.ensureContentInitialized(); - activation.setDone(); }; if (visible || ApplicationManager.getApplication().isUnitTestMode()) { runnable.run(); diff --git a/platform/platform-impl/src/com/intellij/ui/KeyStrokeAdapter.java b/platform/platform-impl/src/com/intellij/ui/KeyStrokeAdapter.java index 020fb241b3ef..cf607d56271a 100644 --- a/platform/platform-impl/src/com/intellij/ui/KeyStrokeAdapter.java +++ b/platform/platform-impl/src/com/intellij/ui/KeyStrokeAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ */ package com.intellij.ui; -import com.intellij.Patches; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; @@ -26,7 +25,6 @@ import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.Locale; import java.util.Map; import java.util.StringTokenizer; @@ -116,7 +114,7 @@ public class KeyStrokeAdapter implements KeyListener { if (Registry.is("actionSystem.extendedKeyCode.disabled")) { return null; } - code = getExtendedKeyCode(event); + code = event.getExtendedKeyCode(); if (code == event.getKeyCode()) { return null; } @@ -146,23 +144,6 @@ public class KeyStrokeAdapter implements KeyListener { return KeyEvent.VK_UNDEFINED == code ? null : KeyStroke.getKeyStroke(code, modifiers, released); } - // TODO: HACK because of Java7 required: - // replace later with event.getExtendedKeyCode() - private static int getExtendedKeyCode(KeyEvent event) { - //noinspection ConstantConditions - assert Patches.USE_REFLECTION_TO_ACCESS_JDK7; - try { - Method method = KeyEvent.class.getMethod("getExtendedKeyCode"); - if (!method.isAccessible()) { - method.setAccessible(true); - } - return (Integer)method.invoke(event); - } - catch (Exception exception) { - return event.getKeyCode(); - } - } - /** * Parses a string and returns the corresponding key stroke. * The string must have the following syntax: diff --git a/platform/platform-impl/src/com/intellij/ui/plaf/gtk/GtkMenuItemUI.java b/platform/platform-impl/src/com/intellij/ui/plaf/gtk/GtkMenuItemUI.java index fd74d0e4863b..e47797729099 100644 --- a/platform/platform-impl/src/com/intellij/ui/plaf/gtk/GtkMenuItemUI.java +++ b/platform/platform-impl/src/com/intellij/ui/plaf/gtk/GtkMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,24 +20,20 @@ import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.UIUtil; import javax.swing.*; -import javax.swing.plaf.MenuItemUI; import javax.swing.plaf.basic.BasicMenuItemUI; +import javax.swing.plaf.synth.ColorType; import javax.swing.plaf.synth.SynthContext; +import javax.swing.plaf.synth.SynthMenuItemUI; import java.awt.*; public class GtkMenuItemUI extends BasicMenuItemUI { private static Icon myCachedCheckIcon = null; - private final BasicMenuItemUI myOriginalUI; + private final SynthMenuItemUI myOriginalUI; private JCheckBoxMenuItem myHiddenItem; - public GtkMenuItemUI(final MenuItemUI originalUI) { - assert isUiAcceptable(originalUI) : originalUI; - myOriginalUI = (BasicMenuItemUI)originalUI; - } - - public static boolean isUiAcceptable(final MenuItemUI ui) { - return ui instanceof BasicMenuItemUI && GtkPaintingUtil.isSynthUI(ui); + public GtkMenuItemUI(SynthMenuItemUI originalUI) { + myOriginalUI = originalUI; } @Override @@ -60,9 +56,9 @@ public class GtkMenuItemUI extends BasicMenuItemUI { resetCachedCheckIcon(); } - private static Icon getCheckIconFromContext(final BasicMenuItemUI originalUI, final JCheckBoxMenuItem item) { + private static Icon getCheckIconFromContext(final SynthMenuItemUI ui, final JCheckBoxMenuItem item) { if (myCachedCheckIcon == null) { - final SynthContext context = GtkPaintingUtil.getSynthContext(originalUI, item); + SynthContext context = ui.getContext(item); myCachedCheckIcon = context.getStyle().getIcon(context, "CheckBoxMenuItem.checkIcon"); } return myCachedCheckIcon; @@ -82,10 +78,12 @@ public class GtkMenuItemUI extends BasicMenuItemUI { if (UIUtil.isMurrineBasedTheme()) { acceleratorFont = menuItem.getFont(); - final Color fg = GtkPaintingUtil.getForeground(myOriginalUI, menuItem); + SynthContext context = myOriginalUI.getContext(menuItem); + Color fg = context.getStyle().getColor(context, ColorType.TEXT_FOREGROUND); acceleratorForeground = UIUtil.mix(fg, menuItem.getBackground(), menuItem.isSelected() ? 0.4 : 0.2); disabledForeground = fg; } + if (checkIcon != null && !(checkIcon instanceof IconWrapper) && !(checkIcon instanceof EmptyIcon)) { checkIcon = new IconWrapper(checkIcon, myOriginalUI); } @@ -97,8 +95,9 @@ public class GtkMenuItemUI extends BasicMenuItemUI { protected void paintText(final Graphics g, final JMenuItem menuItem, final Rectangle textRect, final String text) { if (!menuItem.isEnabled() && UIUtil.isMurrineBasedTheme()) { GtkPaintingUtil.paintDisabledText(myOriginalUI, g, menuItem, textRect, text); - return; } - super.paintText(g, menuItem, textRect, text); + else { + super.paintText(g, menuItem, textRect, text); + } } -} +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ui/plaf/gtk/GtkMenuUI.java b/platform/platform-impl/src/com/intellij/ui/plaf/gtk/GtkMenuUI.java index 43ff684f408f..d2f887d3e0f3 100644 --- a/platform/platform-impl/src/com/intellij/ui/plaf/gtk/GtkMenuUI.java +++ b/platform/platform-impl/src/com/intellij/ui/plaf/gtk/GtkMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,20 +18,15 @@ package com.intellij.ui.plaf.gtk; import com.intellij.util.ui.UIUtil; import javax.swing.*; -import javax.swing.plaf.MenuItemUI; import javax.swing.plaf.basic.BasicMenuUI; +import javax.swing.plaf.synth.SynthMenuUI; import java.awt.*; public class GtkMenuUI extends BasicMenuUI { - private final BasicMenuUI myOriginalUI; + private final SynthMenuUI myOriginalUI; - public GtkMenuUI(final MenuItemUI originalUI) { - assert isUiAcceptable(originalUI) : originalUI; - myOriginalUI = (BasicMenuUI)originalUI; - } - - public static boolean isUiAcceptable(final MenuItemUI ui) { - return ui instanceof BasicMenuUI && GtkPaintingUtil.isSynthUI(ui); + public GtkMenuUI(SynthMenuUI originalUI) { + myOriginalUI = originalUI; } @Override @@ -55,8 +50,9 @@ public class GtkMenuUI extends BasicMenuUI { protected void paintText(final Graphics g, final JMenuItem menuItem, final Rectangle textRect, final String text) { if (!menuItem.isEnabled() && UIUtil.isMurrineBasedTheme()) { GtkPaintingUtil.paintDisabledText(myOriginalUI, g, menuItem, textRect, text); - return; } - super.paintText(g, menuItem, textRect, text); + else { + super.paintText(g, menuItem, textRect, text); + } } -} +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ui/plaf/gtk/GtkPaintingUtil.java b/platform/platform-impl/src/com/intellij/ui/plaf/gtk/GtkPaintingUtil.java index 7da57c850965..b5656f1671e8 100644 --- a/platform/platform-impl/src/com/intellij/ui/plaf/gtk/GtkPaintingUtil.java +++ b/platform/platform-impl/src/com/intellij/ui/plaf/gtk/GtkPaintingUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,31 +15,20 @@ */ package com.intellij.ui.plaf.gtk; -import com.intellij.Patches; import com.intellij.util.ui.UIUtil; import sun.swing.SwingUtilities2; import javax.swing.*; import javax.swing.plaf.MenuItemUI; -import javax.swing.plaf.basic.BasicMenuItemUI; import javax.swing.plaf.synth.ColorType; import javax.swing.plaf.synth.SynthContext; +import javax.swing.plaf.synth.SynthUI; import java.awt.*; -import java.lang.reflect.Method; -// todo[r.sh] get rid of SynthUI reflection after migration to JDK 7 public class GtkPaintingUtil { - private static final String V6_SYNTH_UI_CLASS = "sun.swing.plaf.synth.SynthUI"; - private static final String V7_SYNTH_UI_CLASS = "javax.swing.plaf.synth.SynthUI"; - private GtkPaintingUtil() { } - public static Color getForeground(final BasicMenuItemUI ui, final JMenuItem menuItem) { - final SynthContext context = getSynthContext(ui, menuItem); - return context.getStyle().getColor(context, ColorType.TEXT_FOREGROUND); - } - - public static void paintDisabledText(final BasicMenuItemUI originalUI, + public static void paintDisabledText(final SynthUI originalUI, final Graphics g, final JMenuItem menuItem, final Rectangle textRect, @@ -47,7 +36,8 @@ public class GtkPaintingUtil { final FontMetrics fm = SwingUtilities2.getFontMetrics(menuItem, g); final int index = menuItem.getDisplayedMnemonicIndex(); - final Color fg = getForeground(originalUI, menuItem); + final SynthContext context = originalUI.getContext(menuItem); + final Color fg = context.getStyle().getColor(context, ColorType.TEXT_FOREGROUND); final Color shadow = UIUtil.shade(menuItem.getBackground(), 1.24, 0.5); g.setColor(shadow); @@ -56,32 +46,7 @@ public class GtkPaintingUtil { SwingUtilities2.drawStringUnderlineCharAt(menuItem, g, text, index, textRect.x, textRect.y + fm.getAscent()); } - public static boolean isSynthUI(final MenuItemUI ui) { - Class aClass = ui.getClass(); - - while (aClass != null && aClass.getSimpleName().contains("Synth")) { - final Class[] interfaces = aClass.getInterfaces(); - for (int i = 0, length = interfaces.length; i < length; i++) { - final Class anInterface = interfaces[i]; - if (V6_SYNTH_UI_CLASS.equals(anInterface.getName()) || V7_SYNTH_UI_CLASS.equals(anInterface.getName())) { - return true; - } - } - aClass = aClass.getSuperclass(); - } - - return false; - } - public static SynthContext getSynthContext(final MenuItemUI ui, final JComponent item) { - assert Patches.USE_REFLECTION_TO_ACCESS_JDK7; - try { - final Method getContext = ui.getClass().getMethod("getContext", JComponent.class); - getContext.setAccessible(true); - return (SynthContext)getContext.invoke(ui, item); - } - catch (Exception e) { - throw new RuntimeException(e); - } + return ((SynthUI)ui).getContext(item); } -} +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ui/plaf/gtk/IconWrapper.java b/platform/platform-impl/src/com/intellij/ui/plaf/gtk/IconWrapper.java index 66bbdab856bc..372a19f4a237 100644 --- a/platform/platform-impl/src/com/intellij/ui/plaf/gtk/IconWrapper.java +++ b/platform/platform-impl/src/com/intellij/ui/plaf/gtk/IconWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,16 +18,16 @@ package com.intellij.ui.plaf.gtk; import com.intellij.Patches; import javax.swing.*; -import javax.swing.plaf.MenuItemUI; import javax.swing.plaf.synth.SynthContext; +import javax.swing.plaf.synth.SynthUI; import java.awt.*; import java.lang.reflect.Method; public class IconWrapper implements Icon { private final Icon myIcon; - private final MenuItemUI myOriginalUI; + private final SynthUI myOriginalUI; - public IconWrapper(final Icon icon, final MenuItemUI originalUI) { + public IconWrapper(final Icon icon, final SynthUI originalUI) { myIcon = icon; myOriginalUI = originalUI; } @@ -36,10 +36,9 @@ public class IconWrapper implements Icon { public void paintIcon(final Component c, final Graphics g, final int x, final int y) { if (Patches.USE_REFLECTION_TO_ACCESS_JDK7) { try { - final Method paintIcon = myIcon.getClass().getMethod("paintIcon", SynthContext.class, Graphics.class, - int.class, int.class, int.class, int.class); + Method paintIcon = myIcon.getClass().getMethod("paintIcon", SynthContext.class, Graphics.class, int.class, int.class, int.class, int.class); paintIcon.setAccessible(true); - paintIcon.invoke(myIcon, GtkPaintingUtil.getSynthContext(myOriginalUI, (JComponent)c), g, x, y, getIconWidth(), getIconHeight()); + paintIcon.invoke(myIcon, myOriginalUI.getContext((JComponent)c), g, x, y, getIconWidth(), getIconHeight()); return; } catch (Exception ignore) { } @@ -56,4 +55,4 @@ public class IconWrapper implements Icon { public int getIconHeight() { return myIcon.getIconHeight(); } -} +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ui/popup/MovablePopup.java b/platform/platform-impl/src/com/intellij/ui/popup/MovablePopup.java index 9dea75d03470..fb2ee27c02c0 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/MovablePopup.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/MovablePopup.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,6 @@ import javax.swing.*; import java.awt.*; import java.util.ArrayDeque; -import static com.intellij.Patches.USE_REFLECTION_TO_ACCESS_JDK7; - /** * @author Sergey Malenkov */ @@ -166,7 +164,7 @@ public class MovablePopup { Window view = pop(owner); if (view == null) { view = new JWindow(owner); - setPopupType(view); + view.setType(Window.Type.POPUP); } setAlwaysOnTop(view, myAlwaysOnTop); setWindowFocusable(view, myWindowFocusable); @@ -265,21 +263,6 @@ public class MovablePopup { } } - // TODO: HACK because of Java7 required: - // replace later with window.setType(Window.Type.POPUP) - private static void setPopupType(@NotNull Window window) { - //noinspection ConstantConditions,ConstantAssertCondition - assert USE_REFLECTION_TO_ACCESS_JDK7; - try { - @SuppressWarnings("unchecked") - Class type = (Class)Class.forName("java.awt.Window$Type"); - Object value = Enum.valueOf(type, "POPUP"); - Window.class.getMethod("setType", type).invoke(window, value); - } - catch (Exception ignored) { - } - } - private static JRootPane getRootPane(Window window) { if (window instanceof RootPaneContainer) { RootPaneContainer container = (RootPaneContainer)window; diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index af978ba4e90c..534ffab3da98 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -174,6 +174,9 @@ intention.split.filter.text=Split into filter's chain intention.split.filter.family=Split filter intention.merge.filter.text=Merge filter's chain intention.merge.filter.family=Merge filters +intention.inline.map.inline.text=Inline ''{0}'' body into the next ''{1}'' call +intention.inline.map.merge.text=Merge ''{0}'' call and ''{1}'' call +intention.inline.map.family=Inline stream mapping method intention.introduce.variable.text=Introduce local variable intention.encapsulate.field.text=Encapsulate field intention.implement.abstract.method.family=Implement Abstract Method diff --git a/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt b/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt index cc6b497a61ce..d152cce89576 100644 --- a/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt +++ b/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt @@ -54,7 +54,7 @@ interface SchemeExtensionProvider { } abstract class LazySchemeProcessor(private val nameAttribute: String = "name") : SchemeProcessor() { - open fun getName(attributeProvider: Function): String { + open fun getName(attributeProvider: Function, fileNameWithoutExtension: String): String { return attributeProvider.apply(nameAttribute) ?: throw IllegalStateException("name is missed in the scheme data") } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java index ce2112e80170..c15b0c7ce445 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java @@ -244,7 +244,12 @@ public abstract class GeneralTestEventsProcessor implements Disposable { } public void stopEventProcessing() { - UIUtil.invokeLaterIfNeeded(() -> myTransferToEDTQueue.drain()); + UIUtil.invokeLaterIfNeeded(() -> { + if (myProject.isDisposed()) { + return; + } + myTransferToEDTQueue.drain(); + }); } diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java index 7a55ea8dde42..7cfbe7b8c8c9 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java @@ -846,7 +846,7 @@ public class PlatformTestUtil { public static void assertElementsEqual(final Element expected, final Element actual) throws IOException { if (!JDOMUtil.areElementsEqual(expected, actual)) { - Assert.assertEquals(printElement(expected), printElement(actual)); + Assert.assertEquals(JDOMUtil.writeElement(expected), JDOMUtil.writeElement(actual)); } } @@ -859,12 +859,6 @@ public class PlatformTestUtil { } } - public static String printElement(final Element element) throws IOException { - final StringWriter writer = new StringWriter(); - JDOMUtil.writeElement(element, writer, "\n"); - return writer.getBuffer().toString(); - } - public static String getCommunityPath() { final String homePath = PathManager.getHomePath(); if (new File(homePath, "community/.idea").isDirectory()) { @@ -877,7 +871,6 @@ public class PlatformTestUtil { return getCommunityPath().replace(File.separatorChar, '/') + "/platform/platform-tests/testData/"; } - public static Comparator createComparator(final Queryable.PrintInfo printInfo) { return (o1, o2) -> { String displayText1 = o1.toTestString(printInfo); diff --git a/platform/testFramework/src/com/intellij/testFramework/inspections.kt b/platform/testFramework/src/com/intellij/testFramework/inspections.kt index f557aadd5720..d466de5c7871 100644 --- a/platform/testFramework/src/com/intellij/testFramework/inspections.kt +++ b/platform/testFramework/src/com/intellij/testFramework/inspections.kt @@ -40,7 +40,7 @@ fun configureInspections(tools: Array, Disposer.register(parentDisposable, Disposable { profileManager.deleteProfile(profile) profileManager.setCurrentProfile(null) - clearAllToolsIn(InspectionProfileImpl.getDefaultProfile()) + clearAllToolsIn(InspectionProfileImpl.getBaseProfile()) }) profileManager.addProfile(profile) diff --git a/platform/testFramework/testFramework.iml b/platform/testFramework/testFramework.iml index a3d3621de9e7..1cd589c3830e 100644 --- a/platform/testFramework/testFramework.iml +++ b/platform/testFramework/testFramework.iml @@ -25,7 +25,7 @@ - + diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/assertJEx.kt b/platform/testFramework/testSrc/com/intellij/testFramework/assertJEx.kt index 5d4ad07e94b6..455744a91dde 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/assertJEx.kt +++ b/platform/testFramework/testSrc/com/intellij/testFramework/assertJEx.kt @@ -24,6 +24,7 @@ import org.assertj.core.api.AbstractAssert import org.assertj.core.api.PathAssert import org.assertj.core.internal.Objects import org.jdom.Element +import java.io.File import java.nio.file.Files import java.nio.file.LinkOption import java.nio.file.Path @@ -39,10 +40,23 @@ class JdomAssert(actual: Element?) : AbstractAssert(actual return this } + fun isEqualTo(file: File): JdomAssert { + return isEqualTo(file.readText()) + } + + fun isEqualTo(element: Element): JdomAssert { + isNotNull + + if (!JDOMUtil.areElementsEqual(actual, element)) { + isEqualTo(JDOMUtil.writeElement(element)) + } + return this + } + fun isEqualTo(expected: String): JdomAssert { isNotNull - Objects.instance().assertEqual(info, JDOMUtil.writeElement(actual!!), expected.trimIndent()) + Objects.instance().assertEqual(info, JDOMUtil.writeElement(actual!!), expected.trimIndent().removePrefix("""""").trimStart()) return this } } diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index b87428ba92a0..d54c2328536c 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -491,6 +491,8 @@ diff.divider.repainting.disable.blitting=true diff.divider.repainting.disable.blitting.description=Fix painting glitch on scrolling in diff - disable BLIT_SCROLL_MODE to force repainting with RepaintManager diff.merge.resolve.conflict.action.visible=true diff.merge.resolve.conflict.action.visible.description=Allows to resolve some conflict in merge in one click (with a high probability of wrong result) +diff.merge.resolve.conflict.action.use.greedy.approach=false +diff.merge.resolve.conflict.action.use.greedy.approach.description=Use greedy heuristic in attempt to resolve conflict. This leads to higher amounts of false-positive and true-positive results. diff.enable.psi.highlighting=true diff.enable.psi.highlighting.description=Enable advanced highlighting and code navigation in VCS content in diff viewers. diff.pass.rich.editor.context=false diff --git a/platform/util/src/com/intellij/Patches.java b/platform/util/src/com/intellij/Patches.java index ecb590c7b207..41dd4f41ba27 100644 --- a/platform/util/src/com/intellij/Patches.java +++ b/platform/util/src/com/intellij/Patches.java @@ -71,12 +71,6 @@ public class Patches { */ public static final boolean USE_REFLECTION_TO_ACCESS_JDK8 = Boolean.valueOf(true); - /** - * AtomicIntegerFieldUpdater does not work when SecurityManager is installed. - * See https://bugs.openjdk.java.net/browse/JDK-7103570. - */ - public static final boolean JDK_BUG_ID_7103570 = true; - /** * Support default methods in JDI * See JDK-8042123 @@ -127,5 +121,5 @@ public class Patches { /** * Some HTTP connections lock the context class loader: https://bugs.openjdk.java.net/browse/JDK-8032832 */ - public static boolean JDK_BUG_ID_8032832 = SystemInfo.isJavaVersionAtLeast("1.8.0_20"); + public static final boolean JDK_BUG_ID_8032832 = SystemInfo.isJavaVersionAtLeast("1.8.0_20"); } \ No newline at end of file diff --git a/platform/util/src/com/intellij/util/io/CompressedAppendableFile.java b/platform/util/src/com/intellij/util/io/CompressedAppendableFile.java index 5dd735458341..b9deac071df9 100644 --- a/platform/util/src/com/intellij/util/io/CompressedAppendableFile.java +++ b/platform/util/src/com/intellij/util/io/CompressedAppendableFile.java @@ -291,7 +291,7 @@ public class CompressedAppendableFile { private synchronized void loadAppendBuffer() throws IOException { if (myNextChunkBuffer != null) return; - myNextChunkBuffer = new byte[myAppendBufferLength]; + File tempAppendFile = getIncompleteChunkFile(); if (tempAppendFile.exists()) { myBufferPosition = (int)tempAppendFile.length(); diff --git a/platform/util/src/com/intellij/util/ui/EmptyIcon.java b/platform/util/src/com/intellij/util/ui/EmptyIcon.java index 843eb9a08a05..7b630b1068cb 100644 --- a/platform/util/src/com/intellij/util/ui/EmptyIcon.java +++ b/platform/util/src/com/intellij/util/ui/EmptyIcon.java @@ -32,7 +32,7 @@ import java.util.Map; * @see ColorIcon */ public class EmptyIcon implements Icon, ScalableIcon { - private static final Map cache = new HashMap(); + private static final Map cache = new HashMap(); public static final Icon ICON_16 = create(16); public static final Icon ICON_18 = create(18); @@ -45,19 +45,25 @@ public class EmptyIcon implements Icon, ScalableIcon { private EmptyIcon myScaledCache; public static Icon create(int size) { - Icon icon = cache.get(size); - if (icon == null && size < 129) { - cache.put(size, icon = new EmptyIcon(size, size)); + return create(size, size, true); + } + + private static Icon create(int width, int height, boolean autoScale) { + int size = (width == height) ? width : -1; + EmptyIcon icon = cache.get(size); + if (icon == null) { + icon = new EmptyIcon(width, height); + if (size < JBUI.scale(129) && size > 0) cache.put(size, icon); } - return icon == null ? new EmptyIcon(size, size) : icon; + return autoScale ? icon.scale(JBUI.scale(1f)) : icon; } public static Icon create(int width, int height) { - return width == height ? create(width) : new EmptyIcon(width, height); + return create(width, height, true); } public static Icon create(@NotNull Icon base) { - return create(base.getIconWidth(), base.getIconHeight()); + return create(base.getIconWidth(), base.getIconHeight(), false); } /** diff --git a/platform/vcs-api/src/com/intellij/openapi/localVcs/UpToDateLineNumberProvider.java b/platform/vcs-api/src/com/intellij/openapi/localVcs/UpToDateLineNumberProvider.java index a10f34645ab6..e367ad0ecf7b 100644 --- a/platform/vcs-api/src/com/intellij/openapi/localVcs/UpToDateLineNumberProvider.java +++ b/platform/vcs-api/src/com/intellij/openapi/localVcs/UpToDateLineNumberProvider.java @@ -19,6 +19,7 @@ public interface UpToDateLineNumberProvider { int ABSENT_LINE_NUMBER = -1; int FAKE_LINE_NUMBER = -2; + int getLineCount(); int getLineNumber(int currentNumber); boolean isLineChanged(int currentNumber); boolean isRangeChanged(final int start, final int end); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java index c172a7dca544..9768edae6d92 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java @@ -515,6 +515,11 @@ public class AnnotateDiffViewerAction extends ToggleAction implements DumbAware } return myLocalChangesProvider.isRangeChanged(line1, line2); } + + @Override + public int getLineCount() { + return myLocalChangesProvider.getLineCount(); + } } private static class ThreesideAnnotatorFactory extends ThreesideViewerAnnotatorFactory { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java index 005cd6512791..4e9450b0305e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vcs.actions; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Separator; import com.intellij.openapi.actionSystem.ToggleAction; @@ -27,12 +28,14 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Couple; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.annotate.AnnotationGutterActionProvider; import com.intellij.openapi.vcs.annotate.AnnotationSourceSwitcher; import com.intellij.openapi.vcs.annotate.FileAnnotation; import com.intellij.openapi.vcs.annotate.LineAnnotationAspect; +import com.intellij.openapi.vcs.changes.VcsAnnotationLocalChangesListener; import com.intellij.openapi.vcs.history.VcsFileRevision; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vcs.impl.UpToDateLineNumberProviderImpl; @@ -89,8 +92,23 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware { @NotNull final FileAnnotation fileAnnotation, @NotNull final AbstractVcs vcs, @Nullable final UpToDateLineNumberProvider upToDateLineNumberProvider) { + Disposable disposable = new Disposable() { + @Override + public void dispose() { + fileAnnotation.dispose(); + } + }; + if (fileAnnotation.getFile() != null && fileAnnotation.getFile().isInLocalFileSystem()) { - ProjectLevelVcsManager.getInstance(project).getAnnotationLocalChangesListener().registerAnnotation(fileAnnotation.getFile(), fileAnnotation); + VcsAnnotationLocalChangesListener changesListener = ProjectLevelVcsManager.getInstance(project).getAnnotationLocalChangesListener(); + + changesListener.registerAnnotation(fileAnnotation.getFile(), fileAnnotation); + Disposer.register(disposable, new Disposable() { + @Override + public void dispose() { + changesListener.unregisterAnnotation(fileAnnotation.getFile(), fileAnnotation); + } + }); } editor.getGutter().closeAllAnnotations(); @@ -116,7 +134,7 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware { upToDateLineNumberProvider : new UpToDateLineNumberProviderImpl(editor.getDocument(), project); - final AnnotationPresentation presentation = new AnnotationPresentation(fileAnnotation, getUpToDateLineNumber, switcher); + final AnnotationPresentation presentation = new AnnotationPresentation(fileAnnotation, getUpToDateLineNumber, switcher, disposable); if (currentFile != null && vcs.getCommittedChangesProvider() != null) { presentation.addAction(new ShowDiffFromAnnotation(fileAnnotation, vcs, currentFile)); } @@ -132,7 +150,7 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware { final CurrentRevisionAnnotationFieldGutter currentRevisionGutter = new CurrentRevisionAnnotationFieldGutter(fileAnnotation, revisionAspect, presentation, bgColorMap); final MergeSourceAvailableMarkerGutter mergeSourceGutter = - new MergeSourceAvailableMarkerGutter(fileAnnotation, null, presentation, bgColorMap); + new MergeSourceAvailableMarkerGutter(fileAnnotation, presentation, bgColorMap); SwitchAnnotationSourceAction switchAction = new SwitchAnnotationSourceAction(switcher, editorGutter); presentation.addAction(switchAction); @@ -148,14 +166,14 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware { final LineAnnotationAspect[] aspects = fileAnnotation.getAspects(); for (LineAnnotationAspect aspect : aspects) { - gutters.add(new AnnotationFieldGutter(fileAnnotation, aspect, presentation, bgColorMap)); + gutters.add(new AspectAnnotationFieldGutter(fileAnnotation, aspect, presentation, bgColorMap)); } if (historyIds != null) { gutters.add(new HistoryIdColumn(fileAnnotation, presentation, bgColorMap, historyIds)); } - gutters.add(new HighlightedAdditionalColumn(fileAnnotation, null, presentation, bgColorMap)); + gutters.add(new HighlightedAdditionalColumn(fileAnnotation, presentation, bgColorMap)); final AnnotateActionGroup actionGroup = new AnnotateActionGroup(gutters, editorGutter, bgColorMap); presentation.addAction(actionGroup, 1); gutters.add(new ExtraFieldGutter(fileAnnotation, presentation, bgColorMap, actionGroup)); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java index 2ce48f59a1b5..cb7bd75d0cb1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java @@ -17,18 +17,14 @@ package com.intellij.openapi.vcs.actions; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.EditorGutterAction; import com.intellij.openapi.editor.colors.ColorKey; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.util.Couple; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.annotate.FileAnnotation; -import com.intellij.openapi.vcs.annotate.LineAnnotationAspect; import com.intellij.openapi.vcs.annotate.TextAnnotationPresentation; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.vcsUtil.VcsUtil; -import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,103 +36,61 @@ import java.util.Map; * @author Irina Chernushina * @author Konstantin Bulenkov */ -public class AnnotationFieldGutter implements ActiveAnnotationGutter { +public abstract class AnnotationFieldGutter implements ActiveAnnotationGutter { @NotNull protected final FileAnnotation myAnnotation; - protected final LineAnnotationAspect myAspect; @NotNull private final TextAnnotationPresentation myPresentation; - private final boolean myIsGutterAction; @Nullable private Couple> myColorScheme; AnnotationFieldGutter(@NotNull FileAnnotation annotation, - LineAnnotationAspect aspect, @NotNull TextAnnotationPresentation presentation, @Nullable Couple> colorScheme) { myAnnotation = annotation; - myAspect = aspect; myPresentation = presentation; - myIsGutterAction = myAspect instanceof EditorGutterAction; myColorScheme = colorScheme; } public boolean isGutterAction() { - return myIsGutterAction; - } - - public String getLineText(int line, Editor editor) { - final String value = isAvailable() ? myAspect.getValue(line) : ""; - if (myAspect.getId() == LineAnnotationAspect.AUTHOR && ShowShortenNames.isSet()) { - return shorten(value, ShowShortenNames.getType()); - } - return value; - } - - @Nullable - public static String shorten(String name, ShortNameType type) { - if (name != null) { - // Vasya Pupkin -> Vasya Pupkin - final int[] ind = {name.indexOf('<'), name.indexOf('@'), name.indexOf('>')}; - if (0 < ind[0] && ind[0] < ind[1] && ind[1] < ind[2]) { - return shorten(name.substring(0, ind[0]).trim(), type); - } - - // vasya.pupkin@email.com --> vasya pupkin - if (!name.contains(" ") && name.contains("@")) { //simple e-mail check. john@localhost - final String firstPart = name.substring(0, name.indexOf('@')).replace('.', ' ').replace('_', ' ').replace('-', ' '); - if (firstPart.length() < name.length()) { - return shorten(firstPart, type); - } else { - return firstPart; - } - } - - final List strings = StringUtil.split(name.replace('.', ' ').replace('_', ' ').replace('-', ' '), " "); - if (strings.size() > 1) { - //Middle name check: Vasya S. Pupkin - return StringUtil.capitalize(type == ShortNameType.FIRSTNAME ? strings.get(0) : strings.get(strings.size() - 1)); - } - } - return name; + return false; } @Nullable + @Override public String getToolTip(final int line, final Editor editor) { - return isAvailable() ? XmlStringUtil.escapeString(myAnnotation.getToolTip(line)) : null; + return null; } + @Override public void doAction(int line) { - if (myIsGutterAction) { - ((EditorGutterAction)myAspect).doAction(line); - } } + @Override public Cursor getCursor(final int line) { - if (myIsGutterAction) { - return ((EditorGutterAction)myAspect).getCursor(line); - } else { - return Cursor.getDefaultCursor(); - } - + return Cursor.getDefaultCursor(); } + @Override public EditorFontType getStyle(final int line, final Editor editor) { return myPresentation.getFontType(line); } @Nullable + @Override public ColorKey getColor(final int line, final Editor editor) { return myPresentation.getColor(line); } + @Override public List getPopupActions(int line, final Editor editor) { return myPresentation.getActions(line); } + @Override public void gutterClosed() { - ProjectLevelVcsManager.getInstance(myAnnotation.getProject()).getAnnotationLocalChangesListener().unregisterAnnotation(myAnnotation.getFile(), myAnnotation); - myAnnotation.dispose(); + myPresentation.gutterClosed(); } @Nullable + @Override public Color getBgColor(int line, Editor editor) { if (myColorScheme == null) return null; ColorMode type = ShowAnnotationColorsAction.getType(); @@ -147,23 +101,16 @@ public class AnnotationFieldGutter implements ActiveAnnotationGutter { return colorMap.get(number); } + public boolean isShowByDefault() { + return true; + } + public boolean isAvailable() { - if (myAspect == null) return false; - return VcsUtil.isAspectAvailableByDefault(getID(), myAspect.isShowByDefault()); + return VcsUtil.isAspectAvailableByDefault(getID(), isShowByDefault()); } @Nullable public String getID() { - return myAspect == null ? null : myAspect.getId(); - } - - - public static void main(String[] args) { - assert shorten("Vasya Pavlovich Pupkin ", ShortNameType.FIRSTNAME).equals("Vasya"); - assert shorten("Vasya Pavlovich Pupkin ", ShortNameType.LASTNAME).equals("Pupkin"); - assert shorten("Vasya Pavlovich Pupkin", ShortNameType.FIRSTNAME).equals("Vasya"); - assert shorten("Vasya Pavlovich Pupkin", ShortNameType.LASTNAME).equals("Pupkin"); - assert shorten("vasya.pupkin@localhost.com", ShortNameType.LASTNAME).equals("Pupkin"); - assert shorten("vasya.pupkin@localhost.com", ShortNameType.FIRSTNAME).equals("Vasya"); + return null; } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationPresentation.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationPresentation.java index 08d7b20d0121..28bb81e686a7 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationPresentation.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationPresentation.java @@ -15,13 +15,14 @@ */ package com.intellij.openapi.vcs.actions; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.editor.colors.ColorKey; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.localVcs.UpToDateLineNumberProvider; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vcs.annotate.*; import com.intellij.openapi.vcs.history.VcsRevisionNumber; -import com.intellij.util.Consumer; import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,25 +36,33 @@ class AnnotationPresentation implements TextAnnotationPresentation { @Nullable private final AnnotationSourceSwitcher mySwitcher; private final ArrayList myActions = new ArrayList<>(); + @NotNull private final Disposable myDisposable; + private boolean myDisposed = false; + AnnotationPresentation(@NotNull FileAnnotation fileAnnotation, @NotNull UpToDateLineNumberProvider upToDateLineNumberProvider, - @Nullable final AnnotationSourceSwitcher switcher) { + @Nullable AnnotationSourceSwitcher switcher, + @NotNull Disposable disposable) { myUpToDateLineNumberProvider = upToDateLineNumberProvider; myFileAnnotation = fileAnnotation; mySwitcher = switcher; + myDisposable = disposable; } + @Override public EditorFontType getFontType(final int line) { VcsRevisionNumber revision = myFileAnnotation.originalRevision(line); VcsRevisionNumber currentRevision = myFileAnnotation.getCurrentRevision(); return currentRevision != null && currentRevision.equals(revision) ? EditorFontType.BOLD : EditorFontType.PLAIN; } + @Override public ColorKey getColor(final int line) { if (mySwitcher == null) return AnnotationSource.LOCAL.getColor(); return mySwitcher.getAnnotationSource(line).getColor(); } + @Override public List getActions(int line) { int correctedNumber = myUpToDateLineNumberProvider.getLineNumber(line); for (AnAction action : myActions) { @@ -79,4 +88,11 @@ class AnnotationPresentation implements TextAnnotationPresentation { public void addAction(AnAction action, int index) { myActions.add(index, action); } + + @Override + public void gutterClosed() { + if (myDisposed) return; + myDisposed = true; + Disposer.dispose(myDisposable); + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AspectAnnotationFieldGutter.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AspectAnnotationFieldGutter.java new file mode 100644 index 000000000000..086d8e927918 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AspectAnnotationFieldGutter.java @@ -0,0 +1,94 @@ +/* + * 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.openapi.vcs.actions; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorGutterAction; +import com.intellij.openapi.util.Couple; +import com.intellij.openapi.vcs.annotate.FileAnnotation; +import com.intellij.openapi.vcs.annotate.LineAnnotationAspect; +import com.intellij.openapi.vcs.annotate.TextAnnotationPresentation; +import com.intellij.openapi.vcs.history.VcsRevisionNumber; +import com.intellij.xml.util.XmlStringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.util.Map; + +/** + * @author Irina Chernushina + * @author Konstantin Bulenkov + */ +public class AspectAnnotationFieldGutter extends AnnotationFieldGutter { + @NotNull protected final LineAnnotationAspect myAspect; + private final boolean myIsGutterAction; + + public AspectAnnotationFieldGutter(@NotNull FileAnnotation annotation, + @NotNull LineAnnotationAspect aspect, + @NotNull TextAnnotationPresentation presentation, + @Nullable Couple> colorScheme) { + super(annotation, presentation, colorScheme); + myAspect = aspect; + myIsGutterAction = myAspect instanceof EditorGutterAction; + } + + @Override + public boolean isGutterAction() { + return myIsGutterAction; + } + + @Override + public String getLineText(int line, Editor editor) { + final String value = isAvailable() ? myAspect.getValue(line) : ""; + if (myAspect.getId() == LineAnnotationAspect.AUTHOR) { + return ShortNameType.shorten(value, ShowShortenNames.getType()); + } + return value; + } + + @Nullable + @Override + public String getToolTip(final int line, final Editor editor) { + return isAvailable() ? XmlStringUtil.escapeString(myAnnotation.getToolTip(line)) : null; + } + + @Override + public void doAction(int line) { + if (myIsGutterAction) { + ((EditorGutterAction)myAspect).doAction(line); + } + } + + @Override + public Cursor getCursor(final int line) { + if (myIsGutterAction) { + return ((EditorGutterAction)myAspect).getCursor(line); + } + return super.getCursor(line); + } + + @Override + public boolean isShowByDefault() { + return myAspect.isShowByDefault(); + } + + @Nullable + @Override + public String getID() { + return myAspect.getId(); + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/CurrentRevisionAnnotationFieldGutter.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/CurrentRevisionAnnotationFieldGutter.java index 78bbc5fdcbf9..8a64690392d9 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/CurrentRevisionAnnotationFieldGutter.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/CurrentRevisionAnnotationFieldGutter.java @@ -34,7 +34,7 @@ import java.util.Map; * * @author Konstantin Bulenkov */ -class CurrentRevisionAnnotationFieldGutter extends AnnotationFieldGutter implements Consumer { +class CurrentRevisionAnnotationFieldGutter extends AspectAnnotationFieldGutter implements Consumer { // merge source showing is turned on private boolean myTurnedOn; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ExtraFieldGutter.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ExtraFieldGutter.java index 77828f9fbd9a..dde2dd29a882 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ExtraFieldGutter.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ExtraFieldGutter.java @@ -32,7 +32,7 @@ public class ExtraFieldGutter extends AnnotationFieldGutter { public ExtraFieldGutter(FileAnnotation fileAnnotation, AnnotationPresentation presentation, Couple> bgColorMap, AnnotateActionGroup actionGroup) { - super(fileAnnotation, null, presentation, bgColorMap); + super(fileAnnotation, presentation, bgColorMap); myActionGroup = actionGroup; } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/HighlightedAdditionalColumn.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/HighlightedAdditionalColumn.java index ebc9ed5e8638..56adfb62444c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/HighlightedAdditionalColumn.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/HighlightedAdditionalColumn.java @@ -18,7 +18,6 @@ package com.intellij.openapi.vcs.actions; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.Couple; import com.intellij.openapi.vcs.annotate.FileAnnotation; -import com.intellij.openapi.vcs.annotate.LineAnnotationAspect; import com.intellij.openapi.vcs.annotate.TextAnnotationPresentation; import com.intellij.openapi.vcs.history.VcsRevisionNumber; @@ -28,10 +27,9 @@ import java.util.Map; class HighlightedAdditionalColumn extends AnnotationFieldGutter { HighlightedAdditionalColumn(FileAnnotation annotation, - LineAnnotationAspect aspect, TextAnnotationPresentation presentation, Couple> colorScheme) { - super(annotation, aspect, presentation, colorScheme); + super(annotation, presentation, colorScheme); } @Override diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/HistoryIdColumn.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/HistoryIdColumn.java index 8fe73dc6f0bd..f9013b0c5ba7 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/HistoryIdColumn.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/HistoryIdColumn.java @@ -21,7 +21,6 @@ import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vcs.annotate.FileAnnotation; import com.intellij.openapi.vcs.annotate.TextAnnotationPresentation; import com.intellij.openapi.vcs.history.VcsRevisionNumber; -import com.intellij.vcsUtil.VcsUtil; import java.awt.*; import java.util.Map; @@ -36,7 +35,7 @@ class HistoryIdColumn extends AnnotationFieldGutter { final TextAnnotationPresentation presentation, Couple> colorScheme, Map ids) { - super(annotation, null, presentation, colorScheme); + super(annotation, presentation, colorScheme); myHistoryIds = ids; } @@ -59,8 +58,8 @@ class HistoryIdColumn extends AnnotationFieldGutter { } @Override - public boolean isAvailable() { - return VcsUtil.isAspectAvailableByDefault(getID(), false); + public boolean isShowByDefault() { + return false; } @Override diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/MergeSourceAvailableMarkerGutter.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/MergeSourceAvailableMarkerGutter.java index 6c2ef0729559..375f1d110885 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/MergeSourceAvailableMarkerGutter.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/MergeSourceAvailableMarkerGutter.java @@ -18,7 +18,10 @@ package com.intellij.openapi.vcs.actions; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.ColorKey; import com.intellij.openapi.util.Couple; -import com.intellij.openapi.vcs.annotate.*; +import com.intellij.openapi.vcs.annotate.AnnotationSource; +import com.intellij.openapi.vcs.annotate.AnnotationSourceSwitcher; +import com.intellij.openapi.vcs.annotate.FileAnnotation; +import com.intellij.openapi.vcs.annotate.TextAnnotationPresentation; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.util.Consumer; @@ -33,10 +36,9 @@ class MergeSourceAvailableMarkerGutter extends AnnotationFieldGutter implements private boolean myTurnedOn; MergeSourceAvailableMarkerGutter(FileAnnotation annotation, - LineAnnotationAspect aspect, TextAnnotationPresentation highlighting, Couple> colorScheme) { - super(annotation, aspect, highlighting, colorScheme); + super(annotation, highlighting, colorScheme); } @Override diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShortNameType.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShortNameType.java index c6936797d08b..e7cd4804df2e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShortNameType.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShortNameType.java @@ -16,6 +16,11 @@ package com.intellij.openapi.vcs.actions; import com.intellij.ide.util.PropertiesComponent; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; /** * @author Konstantin Bulenkov @@ -45,4 +50,34 @@ public enum ShortNameType { void set() { PropertiesComponent.getInstance().setValue(KEY, myId); } + + @Nullable + public static String shorten(@Nullable String name, @NotNull ShortNameType type) { + if (name == null) return null; + if (type == NONE) return name; + + // Vasya Pupkin -> Vasya Pupkin + final int[] ind = {name.indexOf('<'), name.indexOf('@'), name.indexOf('>')}; + if (0 < ind[0] && ind[0] < ind[1] && ind[1] < ind[2]) { + name = name.substring(0, ind[0]).trim(); + } + + // vasya.pupkin@email.com --> vasya pupkin + if (!name.contains(" ") && name.contains("@")) { //simple e-mail check. john@localhost + name = name.substring(0, name.indexOf('@')); + } + name = name.replace('.', ' ').replace('_', ' ').replace('-', ' '); + + final List strings = StringUtil.split(name, " "); + if (strings.size() < 2) return name; + + String shortName; + if (type == FIRSTNAME) { + shortName = strings.get(0); + } + else { + shortName = strings.get(strings.size() - 1); + } + return StringUtil.capitalize(shortName); + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowShortenNames.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowShortenNames.java index fe5af07d7279..e10aa4ec1641 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowShortenNames.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowShortenNames.java @@ -47,10 +47,6 @@ public class ShowShortenNames extends ActionGroup { return myChildren; } - public static boolean isSet() { - return getType() != ShortNameType.NONE; - } - public static ShortNameType getType() { for (ShortNameType type : ShortNameType.values()) { if (type.isSet()) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java index 1fca77641739..8d610295d65b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java @@ -25,4 +25,5 @@ public interface TextAnnotationPresentation { EditorFontType getFontType(int line); ColorKey getColor(int line); List getActions(int line); + void gutterClosed(); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java index 921d6432da7c..9cf5a451b544 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java @@ -19,10 +19,8 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.localVcs.UpToDateLineNumberProvider; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.ex.LineStatusTracker; +import org.jetbrains.annotations.Nullable; -/** - * author: lesya - */ public class UpToDateLineNumberProviderImpl implements UpToDateLineNumberProvider { private final Document myDocument; private final LineStatusTrackerManagerI myLineStatusTrackerManagerI; @@ -34,28 +32,51 @@ public class UpToDateLineNumberProviderImpl implements UpToDateLineNumberProvide @Override public boolean isRangeChanged(final int start, final int end) { - LineStatusTracker tracker = myLineStatusTrackerManagerI.getLineStatusTracker(myDocument); - if (tracker == null || !tracker.isOperational()) { + LineStatusTracker tracker = getTracker(); + if (tracker == null) { return false; } - return tracker.isRangeModified(start, end); + else { + return tracker.isRangeModified(start, end); + } } @Override public boolean isLineChanged(int currentNumber) { - LineStatusTracker tracker = myLineStatusTrackerManagerI.getLineStatusTracker(myDocument); - if (tracker == null || !tracker.isOperational()) { + LineStatusTracker tracker = getTracker(); + if (tracker == null) { return false; } - return tracker.isLineModified(currentNumber); + else { + return tracker.isLineModified(currentNumber); + } } @Override public int getLineNumber(int currentNumber) { - LineStatusTracker tracker = myLineStatusTrackerManagerI.getLineStatusTracker(myDocument); - if (tracker == null || !tracker.isOperational()) { + LineStatusTracker tracker = getTracker(); + if (tracker == null) { return currentNumber; } - return tracker.transferLineToVcs(currentNumber, false); + else { + return tracker.transferLineToVcs(currentNumber, false); + } + } + + @Override + public int getLineCount() { + LineStatusTracker tracker = getTracker(); + if (tracker == null) { + return myDocument.getLineCount(); + } + else { + return tracker.getVcsDocument().getLineCount(); + } + } + + @Nullable + private LineStatusTracker getTracker() { + LineStatusTracker tracker = myLineStatusTrackerManagerI.getLineStatusTracker(myDocument); + return tracker != null && tracker.isOperational() ? tracker : null; } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/InMemoryStorage.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/InMemoryStorage.java index 26e753e76861..cb7e15bc0e83 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/InMemoryStorage.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/InMemoryStorage.java @@ -22,15 +22,14 @@ import com.intellij.vcs.log.CommitId; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.VcsLogStorage; import com.intellij.vcs.log.VcsRef; -import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static com.intellij.util.containers.ContainerUtil.canonicalStrategy; + public class InMemoryStorage implements VcsLogStorage { - @SuppressWarnings("unchecked") private final BiDirectionalEnumerator myCommitIdEnumerator = - new BiDirectionalEnumerator<>(1, TObjectHashingStrategy.CANONICAL); - @SuppressWarnings("unchecked") private final BiDirectionalEnumerator myRefsEnumerator = - new BiDirectionalEnumerator<>(1, TObjectHashingStrategy.CANONICAL); + private final BiDirectionalEnumerator myCommitIdEnumerator = new BiDirectionalEnumerator<>(1, canonicalStrategy()); + private final BiDirectionalEnumerator myRefsEnumerator = new BiDirectionalEnumerator<>(1, canonicalStrategy()); @Override public int getCommitIndex(@NotNull Hash hash, @NotNull VirtualFile root) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/ShowGraphHistoryAction.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/ShowGraphHistoryAction.java index 967d4ff20326..fa8cdffcdc75 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/ShowGraphHistoryAction.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/ShowGraphHistoryAction.java @@ -64,7 +64,8 @@ public class ShowGraphHistoryAction extends DumbAwareAction { presentation.setEnabledAndVisible(false); } else { - presentation.setEnabledAndVisible(dataManager.getIndex().isIndexed(root)); + presentation.setVisible(dataManager.getRoots().contains(root)); + presentation.setEnabled(dataManager.getIndex().isIndexed(root)); } } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java index eeac9e9bdd04..698ebd3ec0f0 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java @@ -186,7 +186,7 @@ public class VcsLogGraphTable extends TableWithProgress implements DataProvider, for (int row = 0; row < maxRowsToCheck; row++) { String value = getModel().getValueAt(row, i).toString(); Font font = tableFont; - VcsLogHighlighter.TextStyle style = getStyle(row, i, value, false, false).getTextStyle(); + VcsLogHighlighter.TextStyle style = getStyle(row, i, false, false).getTextStyle(); if (BOLD.equals(style)) { font = tableFont.deriveFont(Font.BOLD); } @@ -336,13 +336,13 @@ public class VcsLogGraphTable extends TableWithProgress implements DataProvider, myHighlighters.clear(); } + @NotNull public SimpleTextAttributes applyHighlighters(@NotNull Component rendererComponent, int row, int column, - String text, boolean hasFocus, final boolean selected) { - VcsLogHighlighter.VcsCommitStyle style = getStyle(row, column, text, hasFocus, selected); + VcsLogHighlighter.VcsCommitStyle style = getStyle(row, column, hasFocus, selected); assert style.getBackground() != null && style.getForeground() != null && style.getTextStyle() != null; @@ -359,14 +359,14 @@ public class VcsLogGraphTable extends TableWithProgress implements DataProvider, return SimpleTextAttributes.REGULAR_ATTRIBUTES; } - public VcsLogHighlighter.VcsCommitStyle getBaseStyle(int row, int column, String text, boolean hasFocus, boolean selected) { - Component dummyRendererComponent = myDummyRenderer.getTableCellRendererComponent(this, text, selected, hasFocus, row, column); + public VcsLogHighlighter.VcsCommitStyle getBaseStyle(int row, int column, boolean hasFocus, boolean selected) { + Component dummyRendererComponent = myDummyRenderer.getTableCellRendererComponent(this, "", selected, hasFocus, row, column); return VcsCommitStyleFactory .createStyle(dummyRendererComponent.getForeground(), dummyRendererComponent.getBackground(), VcsLogHighlighter.TextStyle.NORMAL); } - private VcsLogHighlighter.VcsCommitStyle getStyle(int row, int column, String text, boolean hasFocus, boolean selected) { - VcsLogHighlighter.VcsCommitStyle baseStyle = getBaseStyle(row, column, text, hasFocus, selected); + private VcsLogHighlighter.VcsCommitStyle getStyle(int row, int column, boolean hasFocus, boolean selected) { + VcsLogHighlighter.VcsCommitStyle baseStyle = getBaseStyle(row, column, hasFocus, selected); VisibleGraph visibleGraph = getVisibleGraph(); if (row < 0 || row >= visibleGraph.getVisibleCommitCount()) { @@ -549,7 +549,7 @@ public class VcsLogGraphTable extends TableWithProgress implements DataProvider, protected void paintFooter(@NotNull Graphics g, int x, int y, int width, int height) { int lastRow = getRowCount() - 1; if (lastRow >= 0) { - g.setColor(getStyle(lastRow, GraphTableModel.COMMIT_COLUMN, "", hasFocus(), false).getBackground()); + g.setColor(getStyle(lastRow, GraphTableModel.COMMIT_COLUMN, hasFocus(), false).getBackground()); g.fillRect(x, y, width, height); if (myUi.isMultipleRoots()) { g.setColor(getRootBackgroundColor(getModel().getRoot(lastRow), myUi.getColorManager())); @@ -561,7 +561,7 @@ public class VcsLogGraphTable extends TableWithProgress implements DataProvider, } } else { - g.setColor(getBaseStyle(lastRow, GraphTableModel.COMMIT_COLUMN, "", hasFocus(), false).getBackground()); + g.setColor(getBaseStyle(lastRow, GraphTableModel.COMMIT_COLUMN, hasFocus(), false).getBackground()); g.fillRect(x, y, width, height); } } @@ -626,7 +626,7 @@ public class VcsLogGraphTable extends TableWithProgress implements DataProvider, } myColor = color; - Color background = ((VcsLogGraphTable)table).getStyle(row, column, text, hasFocus, isSelected).getBackground(); + Color background = ((VcsLogGraphTable)table).getStyle(row, column, hasFocus, isSelected).getBackground(); assert background != null; myBorderColor = background; setForeground(UIUtil.getTableForeground(false)); @@ -655,7 +655,7 @@ public class VcsLogGraphTable extends TableWithProgress implements DataProvider, if (value == null) { return; } - append(value.toString(), applyHighlighters(this, row, column, value.toString(), hasFocus, selected)); + append(value.toString(), applyHighlighters(this, row, column, hasFocus, selected)); } public int getHorizontalTextPadding() { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRenderer.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRenderer.java index 0591dd7ac0bb..bf43444298f2 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRenderer.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRenderer.java @@ -20,6 +20,7 @@ import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.VcsRef; import com.intellij.vcs.log.VcsRefType; import com.intellij.vcs.log.data.VcsLogData; +import com.intellij.vcs.log.graph.EdgePrintElement; import com.intellij.vcs.log.graph.PrintElement; import com.intellij.vcs.log.graph.VisibleGraph; import com.intellij.vcs.log.paint.GraphCellPainter; @@ -135,10 +136,10 @@ public class GraphCommitCellRenderer extends ColoredTableCellRenderer { graphPadding = 0; } - SimpleTextAttributes style = myGraphTable.applyHighlighters(this, row, column, "", hasFocus, isSelected); + SimpleTextAttributes style = myGraphTable.applyHighlighters(this, row, column, hasFocus, isSelected); Collection refs = cell.getRefsToThisCommit(); - Color foreground = ObjectUtils.assertNotNull(myGraphTable.getBaseStyle(row, column, "", hasFocus, isSelected).getForeground()); + Color foreground = ObjectUtils.assertNotNull(myGraphTable.getBaseStyle(row, column, hasFocus, isSelected).getForeground()); myExpanded = myGraphTable.getExpandableItemsHandler().getExpandedItems().contains(new TableCell(row, column)); if (myFadeOutPainter != null) { myFadeOutPainter.customize(refs, row, column, table, foreground); @@ -165,19 +166,24 @@ public class GraphCommitCellRenderer extends ColoredTableCellRenderer { private PaintInfo getGraphImage(int row) { VisibleGraph graph = myGraphTable.getVisibleGraph(); Collection printElements = graph.getRowInfo(row).getPrintElements(); - int maxIndex = 0; + double maxIndex = 0; for (PrintElement printElement : printElements) { maxIndex = Math.max(maxIndex, printElement.getPositionInCurrentRow()); + if (printElement instanceof EdgePrintElement) { + maxIndex = Math.max(maxIndex, + (printElement.getPositionInCurrentRow() + ((EdgePrintElement)printElement).getPositionInOtherRow()) / 2.0); + } } maxIndex++; + maxIndex = Math.max(maxIndex, Math.min(MAX_GRAPH_WIDTH, graph.getRecommendedWidth())); - final BufferedImage image = UIUtil - .createImage(PaintParameters.getNodeWidth(myGraphTable.getRowHeight()) * (maxIndex + 4), myGraphTable.getRowHeight(), - BufferedImage.TYPE_INT_ARGB); + BufferedImage image = UIUtil.createImage((int)(PaintParameters.getNodeWidth(myGraphTable.getRowHeight()) * (maxIndex + 2)), + myGraphTable.getRowHeight(), + BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = image.createGraphics(); myPainter.draw(g2, printElements); - int width = maxIndex * PaintParameters.getNodeWidth(myGraphTable.getRowHeight()); + int width = (int)(maxIndex * PaintParameters.getNodeWidth(myGraphTable.getRowHeight())); return new PaintInfo(image, width); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/AtomicFieldUpdaterIssuesInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/AtomicFieldUpdaterIssuesInspection.java index c3739d4bf34b..b72a0e62f291 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/AtomicFieldUpdaterIssuesInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/AtomicFieldUpdaterIssuesInspection.java @@ -129,7 +129,8 @@ public class AtomicFieldUpdaterIssuesInspection extends BaseInspection { } final PsiClassObjectAccessExpression objectAccessExpression = (PsiClassObjectAccessExpression)argument2; final PsiType type = objectAccessExpression.getOperand().getType(); - if (!TypeUtils.areConvertible(type, field.getType())) { + final PsiType substFieldType = classType.resolveGenerics().getSubstitutor().substitute(field.getType()); + if (!substFieldType.isAssignableFrom(type)) { registerError(lastArgument, InspectionGadgetsBundle.message("field.incorrect.type.problem.descriptor", fieldName, type.getPresentableText())); return; diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/MethodRefCanBeReplacedWithLambdaInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/MethodRefCanBeReplacedWithLambdaInspection.java index bb34d5cb9e9b..4d755dcf77d1 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/MethodRefCanBeReplacedWithLambdaInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/MethodRefCanBeReplacedWithLambdaInspection.java @@ -74,6 +74,16 @@ public class MethodRefCanBeReplacedWithLambdaInspection extends BaseInspection { return null; } + public static boolean isWithSideEffects(PsiMethodReferenceExpression methodReferenceExpression) { + final PsiExpression qualifierExpression = methodReferenceExpression.getQualifierExpression(); + if (qualifierExpression != null) { + final List sideEffects = new ArrayList<>(); + SideEffectChecker.checkSideEffects(qualifierExpression, sideEffects); + return !sideEffects.isEmpty(); + } + return false; + } + private static class MethodRefToLambdaVisitor extends BaseInspectionVisitor { @Override public void visitMethodReferenceExpression(PsiMethodReferenceExpression methodReferenceExpression) { @@ -91,16 +101,6 @@ public class MethodRefCanBeReplacedWithLambdaInspection extends BaseInspection { if (onTheFly || ApplicationManager.getApplication().isUnitTestMode()) return SideEffectsMethodRefToLambdaFix::new; return null; } - - private static boolean isWithSideEffects(PsiMethodReferenceExpression methodReferenceExpression) { - final PsiExpression qualifierExpression = methodReferenceExpression.getQualifierExpression(); - if (qualifierExpression != null) { - final List sideEffects = new ArrayList<>(); - SideEffectChecker.checkSideEffects(qualifierExpression, sideEffects); - return !sideEffects.isEmpty(); - } - return false; - } } private static class MethodRefToLambdaFix extends InspectionGadgetsFix { diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightProfile.java b/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightProfile.java index b880fbad0ffa..642f5e79ac6b 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightProfile.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightProfile.java @@ -34,7 +34,7 @@ public class CopyrightProfile extends ProfileEx { //read external public CopyrightProfile() { - super("", new SmartSerializer()); + this(""); } public CopyrightProfile(String profileName) { diff --git a/plugins/eclipse/testData/iml/allProps/expected/expected.iml b/plugins/eclipse/testData/iml/allProps/expected/expected.iml index 73c02983b9bd..dfd2fa8ea05d 100644 --- a/plugins/eclipse/testData/iml/allProps/expected/expected.iml +++ b/plugins/eclipse/testData/iml/allProps/expected/expected.iml @@ -1,111 +1,109 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseIml2ModulesTest.java b/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseIml2ModulesTest.java index 505d9b606840..d9d8bd451470 100644 --- a/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseIml2ModulesTest.java +++ b/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseIml2ModulesTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,6 @@ package org.jetbrains.idea.eclipse; import org.jetbrains.annotations.NotNull; public class EclipseIml2ModulesTest extends Eclipse2ModulesTest { - @Override protected String getTestPath() { return "iml"; diff --git a/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseImlTest.java b/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseImlTest.java index 8a2f6ed77023..c7696a6b3732 100644 --- a/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseImlTest.java +++ b/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseImlTest.java @@ -40,13 +40,14 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.IdeaTestCase; -import com.intellij.testFramework.PlatformTestUtil; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.idea.eclipse.conversion.EclipseClasspathReader; import java.io.File; +import static com.intellij.testFramework.Assertions.assertThat; + public class EclipseImlTest extends IdeaTestCase { @NonNls private static final String JUNIT = "JUNIT"; @@ -78,14 +79,9 @@ public class EclipseImlTest extends IdeaTestCase { String communityLib = FileUtil.toSystemIndependentName(PathManagerEx.findFileUnderCommunityHome("lib").getAbsolutePath()); fileText = fileText.replaceAll("\\$" + JUNIT + "\\$", communityLib); final Element classpathElement = JDOMUtil.loadDocument(fileText).getRootElement(); - final Module module = WriteCommandAction.runWriteCommandAction(null, new Computable() { - @Override - public Module compute() { - return ModuleManager.getInstance(project) - .newModule(new File(path) + File.separator + EclipseProjectFinder - .findProjectName(path) + IdeaXml.IML_EXT, StdModuleTypes.JAVA.getId()); - } - }); + final Module module = WriteCommandAction.runWriteCommandAction(null, (Computable)() -> ModuleManager.getInstance(project) + .newModule(new File(path) + File.separator + EclipseProjectFinder + .findProjectName(path) + IdeaXml.IML_EXT, StdModuleTypes.JAVA.getId())); final ModifiableRootModel rootModel = ModuleRootManager.getInstance(module).getModifiableModel(); EclipseClasspathReader classpathReader = new EclipseClasspathReader(path, project, null); classpathReader.init(rootModel); @@ -100,11 +96,9 @@ public class EclipseImlTest extends IdeaTestCase { PathMacroManager.getInstance(project).collapsePaths(actualImlElement); PathMacros.getInstance().removeMacro(JUNIT); - Element expectedIml = JDOMUtil.load(new File(project.getBaseDir().getPath() + "/expected", "expected.iml")); - PlatformTestUtil.assertElementsEqual(expectedIml, actualImlElement); + assertThat(actualImlElement).isEqualTo(new File(project.getBaseDir().getPath() + "/expected", "expected.iml")); } - public void testWorkspaceOnly() throws Exception { doTest(); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java index 20ba58c85a2a..85eb2bfabf2d 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java @@ -244,8 +244,14 @@ public class GithubApiUtil { @NotNull public static List getUserRepos(@NotNull GithubConnection connection) throws IOException { + return getUserRepos(connection, false); + } + + @NotNull + public static List getUserRepos(@NotNull GithubConnection connection, boolean allAssociated) throws IOException { try { - String path = "/user/repos?" + PER_PAGE; + String type = allAssociated ? "" : "type=owner&"; + String path = "/user/repos?" + type + PER_PAGE; return loadAll(connection, path, GithubRepo[].class, ACCEPT_V3_JSON); } catch (GithubConfusingException e) { @@ -257,7 +263,7 @@ public class GithubApiUtil { @NotNull public static List getUserRepos(@NotNull GithubConnection connection, @NotNull String user) throws IOException { try { - String path = "/users/" + user + "/repos?" + PER_PAGE; + String path = "/users/" + user + "/repos?type=owner&" + PER_PAGE; return loadAll(connection, path, GithubRepo[].class, ACCEPT_V3_JSON); } catch (GithubConfusingException e) { @@ -271,15 +277,10 @@ public class GithubApiUtil { try { List repos = new ArrayList<>(); - repos.addAll(getUserRepos(connection)); + repos.addAll(getUserRepos(connection, true)); // We already can return something useful from getUserRepos, so let's ignore errors. // One of this may not exist in GitHub enterprise - try { - repos.addAll(getMembershipRepos(connection)); - } - catch (GithubAuthenticationException | GithubStatusCodeException ignore) { - } try { repos.addAll(getWatchedRepos(connection)); } @@ -295,21 +296,7 @@ public class GithubApiUtil { } @NotNull - public static List getMembershipRepos(@NotNull GithubConnection connection) throws IOException { - String orgsPath = "/user/orgs?" + PER_PAGE; - List orgs = loadAll(connection, orgsPath, GithubOrg[].class); - - List repos = new ArrayList<>(); - for (GithubOrg org : orgs) { - String path = "/orgs/" + org.getLogin() + "/repos?type=member&" + PER_PAGE; - repos.addAll(loadAll(connection, path, GithubRepoOrg[].class, ACCEPT_V3_JSON)); - } - - return repos; - } - - @NotNull - public static List getWatchedRepos(@NotNull GithubConnection connection) throws IOException { + private static List getWatchedRepos(@NotNull GithubConnection connection) throws IOException { String pathWatched = "/user/subscriptions?" + PER_PAGE; return loadAll(connection, pathWatched, GithubRepo[].class, ACCEPT_V3_JSON); } diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubRequestPagingTest.java b/plugins/github/test/org/jetbrains/plugins/github/GithubRequestQueringTest.java similarity index 63% rename from plugins/github/test/org/jetbrains/plugins/github/GithubRequestPagingTest.java rename to plugins/github/test/org/jetbrains/plugins/github/GithubRequestQueringTest.java index fe205e2f4269..a85fee484d2c 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubRequestPagingTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubRequestQueringTest.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.github; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.plugins.github.api.GithubApiUtil; import org.jetbrains.plugins.github.api.GithubConnection; import org.jetbrains.plugins.github.api.data.GithubRepo; @@ -28,15 +29,14 @@ import static org.junit.Assume.assumeNotNull; /** * @author Aleksey Pivovarov */ -public class GithubRequestPagingTest extends GithubTest { +public class GithubRequestQueringTest extends GithubTest { @Override protected void beforeTest() throws Exception { assumeNotNull(myLogin2); } - public void testAvailableRepos() throws Throwable { - + public void testPagination() throws Throwable { GithubConnection connection = new GithubConnection(myGitHubSettings.getAuthData(), true); try { List availableRepos = GithubApiUtil.getUserRepos(connection, myLogin2); @@ -56,4 +56,20 @@ public class GithubRequestPagingTest extends GithubTest { connection.close(); } } + + public void testOwnRepos() throws Throwable { + List result = GithubApiUtil.getUserRepos(new GithubConnection(myAuth)); + + assertTrue(ContainerUtil.exists(result, (it) -> it.getName().equals("example"))); + assertTrue(ContainerUtil.exists(result, (it) -> it.getName().equals("PullRequestTest"))); + assertFalse(ContainerUtil.exists(result, (it) -> it.getName().equals("org_repo"))); + } + + public void testAllRepos() throws Throwable { + List result = GithubApiUtil.getUserRepos(new GithubConnection(myAuth), true); + + assertTrue(ContainerUtil.exists(result, (it) -> it.getName().equals("example"))); + assertTrue(ContainerUtil.exists(result, (it) -> it.getName().equals("PullRequestTest"))); + assertTrue(ContainerUtil.exists(result, (it) -> it.getName().equals("org_repo"))); + } } diff --git a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt index 20e7fe6b5b7d..403347778b5a 100644 --- a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt +++ b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt @@ -16,6 +16,7 @@ package org.jetbrains.java.decompiler import com.intellij.execution.filters.LineNumbersMapping +import com.intellij.icons.AllIcons import com.intellij.ide.highlighter.JavaFileType import com.intellij.ide.plugins.PluginManagerCore import com.intellij.ide.util.PropertiesComponent @@ -28,6 +29,7 @@ import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.DefaultProjectFactory +import com.intellij.openapi.project.Project import com.intellij.openapi.ui.DialogWrapper import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.registry.Registry @@ -40,17 +42,26 @@ import com.intellij.psi.PsiPackage import com.intellij.psi.codeStyle.CodeStyleSettingsManager import com.intellij.psi.compiled.ClassFileDecompilers import com.intellij.psi.impl.compiled.ClsFileImpl +import com.intellij.ui.Gray +import com.intellij.ui.components.JBLabel +import com.intellij.ui.components.JBPanel import com.intellij.util.containers.ContainerUtil +import com.intellij.util.ui.JBUI +import com.intellij.util.ui.UIUtil import org.jetbrains.annotations.TestOnly import org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences import org.jetbrains.java.decompiler.main.extern.IResultSaver +import java.awt.BorderLayout import java.io.File import java.util.* import java.util.concurrent.Callable import java.util.concurrent.Future import java.util.jar.Manifest +import javax.swing.BorderFactory +import javax.swing.JComponent +import javax.swing.JEditorPane class IdeaDecompiler : ClassFileDecompilers.Light() { companion object { @@ -239,4 +250,44 @@ class IdeaDecompiler : ClassFileDecompilers.Light() { return -1 } } + + private class LegalNoticeDialog(project: Project, file: VirtualFile) : DialogWrapper(project) { + companion object { + val POSTPONE_EXIT_CODE = DialogWrapper.CANCEL_EXIT_CODE + val DECLINE_EXIT_CODE = DialogWrapper.NEXT_USER_EXIT_CODE + } + + private var myMessage: JEditorPane? = null + + init { + title = IdeaDecompilerBundle.message("legal.notice.title", StringUtil.last(file.path, 40, true)) + setOKButtonText(IdeaDecompilerBundle.message("legal.notice.action.accept")) + setCancelButtonText(IdeaDecompilerBundle.message("legal.notice.action.postpone")) + init() + pack() + } + + override fun createCenterPanel(): JComponent? { + val iconPanel = JBPanel>(BorderLayout()) + iconPanel.add(JBLabel(AllIcons.General.WarningDialog), BorderLayout.NORTH) + + val message = JEditorPane() + myMessage = message + message.editorKit = UIUtil.getHTMLEditorKit() + message.isEditable = false + message.preferredSize = JBUI.size(500, 100) + message.border = BorderFactory.createLineBorder(Gray._200) + message.text = "
${IdeaDecompilerBundle.message("legal.notice.text")}
" + + val panel = JBPanel>(BorderLayout(JBUI.scale(10), 0)) + panel.add(iconPanel, BorderLayout.WEST) + panel.add(message, BorderLayout.CENTER) + return panel + } + + override fun createActions() = + arrayOf(okAction, DialogWrapperExitAction(IdeaDecompilerBundle.message("legal.notice.action.reject"), DECLINE_EXIT_CODE), cancelAction) + + override fun getPreferredFocusedComponent() = myMessage + } } \ No newline at end of file diff --git a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/LegalNoticeDialog.java b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/LegalNoticeDialog.java deleted file mode 100644 index ec0492a90e49..000000000000 --- a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/LegalNoticeDialog.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jetbrains.java.decompiler; - -import com.intellij.icons.AllIcons; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.Gray; -import com.intellij.ui.components.JBLabel; -import com.intellij.ui.components.JBPanel; -import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; - -class LegalNoticeDialog extends DialogWrapper { - public static final int POSTPONE_EXIT_CODE = CANCEL_EXIT_CODE; - public static final int DECLINE_EXIT_CODE = NEXT_USER_EXIT_CODE; - - private JEditorPane myMessage; - - public LegalNoticeDialog(Project project, VirtualFile file) { - super(project); - setTitle(IdeaDecompilerBundle.message("legal.notice.title", StringUtil.last(file.getPath(), 40, true))); - setOKButtonText(IdeaDecompilerBundle.message("legal.notice.action.accept")); - setCancelButtonText(IdeaDecompilerBundle.message("legal.notice.action.postpone")); - init(); - pack(); - } - - @Nullable - @Override - protected JComponent createCenterPanel() { - JPanel iconPanel = new JBPanel(new BorderLayout()); - iconPanel.add(new JBLabel(AllIcons.General.WarningDialog), BorderLayout.NORTH); - - myMessage = new JEditorPane(); - myMessage.setEditorKit(UIUtil.getHTMLEditorKit()); - myMessage.setEditable(false); - myMessage.setPreferredSize(JBUI.size(500, 100)); - myMessage.setBorder(BorderFactory.createLineBorder(Gray._200)); - String text = "
" + IdeaDecompilerBundle.message("legal.notice.text") + "
"; - myMessage.setText(text); - - JPanel panel = new JBPanel(new BorderLayout(10, 0)); - panel.add(iconPanel, BorderLayout.WEST); - panel.add(myMessage, BorderLayout.CENTER); - return panel; - } - - @NotNull - @Override - protected Action[] createActions() { - return new Action[]{ - getOKAction(), - new DialogWrapperAction(IdeaDecompilerBundle.message("legal.notice.action.reject")) { - @Override - protected void doAction(ActionEvent e) { - close(DECLINE_EXIT_CODE); - } - }, - getCancelAction()}; - } - - @Nullable - @Override - public JComponent getPreferredFocusedComponent() { - return myMessage; - } -} \ No newline at end of file diff --git a/plugins/settings-repository/src/IcsManager.kt b/plugins/settings-repository/src/IcsManager.kt index 03ddf6ec335a..492116735276 100644 --- a/plugins/settings-repository/src/IcsManager.kt +++ b/plugins/settings-repository/src/IcsManager.kt @@ -23,8 +23,8 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.PathManager import com.intellij.openapi.components.RoamingType import com.intellij.openapi.components.stateStore -import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.catchAndLog +import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.progress.runBackgroundableTask import com.intellij.openapi.project.Project import com.intellij.openapi.project.impl.ProjectLifecycleListener @@ -42,7 +42,7 @@ import kotlin.properties.Delegates internal const val PLUGIN_NAME = "Settings Repository" -internal val LOG: Logger = Logger.getInstance(IcsManager::class.java) +internal val LOG = logger() val icsManager by lazy(LazyThreadSafetyMode.NONE) { ApplicationLoadListener.EP_NAME.findExtension(IcsApplicationLoadListener::class.java).icsManager diff --git a/plugins/settings-repository/src/sync.kt b/plugins/settings-repository/src/sync.kt index decfaf44585e..59ebb1699ec9 100644 --- a/plugins/settings-repository/src/sync.kt +++ b/plugins/settings-repository/src/sync.kt @@ -17,15 +17,14 @@ package org.jetbrains.settingsRepository import com.intellij.configurationStore.* import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.ModalityState import com.intellij.openapi.application.impl.ApplicationImpl +import com.intellij.openapi.application.invokeAndWaitIfNeed import com.intellij.openapi.components.StateStorage import com.intellij.openapi.components.stateStore import com.intellij.openapi.options.SchemeManagerFactory import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.runModalTask import com.intellij.openapi.project.Project -import com.intellij.openapi.util.Ref import com.intellij.util.SmartList import com.intellij.util.messages.MessageBus import gnu.trove.THashSet @@ -142,7 +141,6 @@ internal class SyncManager(private val icsManager: IcsManager, private val autoS } internal fun updateStoragesFromStreamProvider(store: ComponentStoreImpl, updateResult: UpdateResult, messageBus: MessageBus, reloadAllSchemes: Boolean = false): Boolean { - val changedComponentNames = LinkedHashSet() val (changed, deleted) = (store.storageManager as StateStorageManagerImpl).getCachedFileStorages(updateResult.changed, updateResult.deleted, ::toIdeaPath) val schemeManagersToReload = SmartList>() @@ -168,9 +166,8 @@ internal fun updateStoragesFromStreamProvider(store: ComponentStoreImpl, updateR return false } - val result = Ref.create(false) - ApplicationManager.getApplication().invokeAndWait(Runnable { - val notReloadableComponents: Collection + return invokeAndWaitIfNeed { + val changedComponentNames = LinkedHashSet() updateStateStorage(changedComponentNames, changed, false) updateStateStorage(changedComponentNames, deleted, true) @@ -179,20 +176,17 @@ internal fun updateStoragesFromStreamProvider(store: ComponentStoreImpl, updateR } if (changedComponentNames.isEmpty()) { - return@Runnable + return@invokeAndWaitIfNeed false } - notReloadableComponents = store.getNotReloadableComponents(changedComponentNames) - + val notReloadableComponents = store.getNotReloadableComponents(changedComponentNames) val changedStorageSet = THashSet(changed) changedStorageSet.addAll(deleted) runBatchUpdate(messageBus) { store.reinitComponents(changedComponentNames, changedStorageSet, notReloadableComponents) } - - result.set(!notReloadableComponents.isEmpty() && askToRestart(store, notReloadableComponents, null, true)) - }, ModalityState.defaultModalityState()) - return result.get() + return@invokeAndWaitIfNeed !notReloadableComponents.isEmpty() && askToRestart(store, notReloadableComponents, null, true) + } } private fun updateStateStorage(changedComponentNames: MutableSet, stateStorages: Collection, deleted: Boolean) { diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/AbstractTestNGInClassConfigurationProducer.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/AbstractTestNGInClassConfigurationProducer.java index dcdb4cf59d6f..4198e3529415 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/AbstractTestNGInClassConfigurationProducer.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/AbstractTestNGInClassConfigurationProducer.java @@ -47,7 +47,7 @@ public abstract class AbstractTestNGInClassConfigurationProducer extends TestNGC } private static boolean isTestNGClass(PsiClass psiClass) { - return psiClass != null && PsiClassUtil.isRunnableClass(psiClass, true, false) && TestNGUtil.hasTest(psiClass); + return psiClass != null && TestNGUtil.hasTest(psiClass); } @Override diff --git a/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java b/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java index f18214ac5287..6a885e88d589 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java +++ b/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java @@ -192,6 +192,20 @@ public class TestNGUtil { } public static boolean hasTest(PsiModifierListOwner element, boolean checkHierarchy, boolean checkDisabled, boolean checkJavadoc) { + final PsiClass aClass; + if (element instanceof PsiClass) { + aClass = ((PsiClass)element); + } + else if (element instanceof PsiMethod) { + aClass = ((PsiMethod)element).getContainingClass(); + } + else { + aClass = null; + } + + if (aClass == null || !PsiClassUtil.isRunnableClass(aClass, true, false)) { + return false; + } //LanguageLevel effectiveLanguageLevel = element.getManager().getEffectiveLanguageLevel(); //boolean is15 = effectiveLanguageLevel != LanguageLevel.JDK_1_4 && effectiveLanguageLevel != LanguageLevel.JDK_1_3; boolean hasAnnotation = AnnotationUtil.isAnnotated(element, TEST_ANNOTATION_FQN, checkHierarchy, true); @@ -474,7 +488,7 @@ public class TestNGUtil { } public static boolean isTestNGClass(PsiClass psiClass) { - return hasTest(psiClass, true, false, false); + return hasTest(psiClass); } public static boolean checkTestNGInClasspath(PsiElement psiElement) { diff --git a/plugins/testng/testData/inspection/dependsOn/Dependencies.java b/plugins/testng/testData/inspection/dependsOn/Dependencies.java index fc095a3ecd3d..d5110bc7507a 100644 --- a/plugins/testng/testData/inspection/dependsOn/Dependencies.java +++ b/plugins/testng/testData/inspection/dependsOn/Dependencies.java @@ -1,5 +1,5 @@ import org.testng.annotations.*; - class MyTest { +public class Dependencies { @Test(dependsOnMethods = "beforeMethod") public void testFoo() throws Exception { } diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_signature.py b/python/helpers/pydev/_pydevd_bundle/pydevd_signature.py index 8203abca50f4..2ec20ed63b10 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_signature.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_signature.py @@ -7,7 +7,7 @@ else: trace._warn = lambda *args: None # workaround for http://bugs.python.org/issue17143 (PY-8706) from _pydevd_bundle.pydevd_comm import CMD_SIGNATURE_CALL_TRACE, NetCommand -from _pydevd_bundle import pydevd_vars +from _pydevd_bundle import pydevd_xml from _pydevd_bundle.pydevd_constants import xrange, dict_iter_items from _pydevd_bundle import pydevd_utils from _pydevd_bundle.pydevd_utils import get_clsname_for_code @@ -153,13 +153,13 @@ class CallSignatureCache(object): def create_signature_message(signature): cmdTextList = [""] - cmdTextList.append('' % (pydevd_vars.make_valid_xml_value(signature.file), pydevd_vars.make_valid_xml_value(signature.name))) + cmdTextList.append('' % (pydevd_xml.make_valid_xml_value(signature.file), pydevd_xml.make_valid_xml_value(signature.name))) for arg in signature.args: - cmdTextList.append('' % (pydevd_vars.make_valid_xml_value(arg[0]), pydevd_vars.make_valid_xml_value(arg[1]))) + cmdTextList.append('' % (pydevd_xml.make_valid_xml_value(arg[0]), pydevd_xml.make_valid_xml_value(arg[1]))) if signature.return_type is not None: - cmdTextList.append('' % (pydevd_vars.make_valid_xml_value(signature.return_type))) + cmdTextList.append('' % (pydevd_xml.make_valid_xml_value(signature.return_type))) cmdTextList.append("") cmdText = ''.join(cmdTextList) diff --git a/python/src/com/jetbrains/python/codeInsight/PySubstitutionChunkReference.java b/python/src/com/jetbrains/python/codeInsight/PySubstitutionChunkReference.java index d32c798fab60..c052d9680976 100644 --- a/python/src/com/jetbrains/python/codeInsight/PySubstitutionChunkReference.java +++ b/python/src/com/jetbrains/python/codeInsight/PySubstitutionChunkReference.java @@ -62,9 +62,9 @@ public class PySubstitutionChunkReference extends PsiReferenceBase chunks = PyStringFormatParser.filterSubstitutions( - PyStringFormatParser.parseNewStyleFormat(element.getText())); + PyStringFormatParser.parseNewStyleFormat(element.getStringValue())); return getReferencesFromChunks(element, chunks, false); } private static PsiReference[] getReferencesFromPercentString(@NotNull final PyStringLiteralExpression element) { final List - chunks = PyStringFormatParser.filterSubstitutions(PyStringFormatParser.parsePercentFormat(element.getText())); + chunks = PyStringFormatParser.filterSubstitutions(PyStringFormatParser.parsePercentFormat(element.getStringValue())); return getReferencesFromChunks(element, chunks, true); } diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyDocstringCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyDocstringCompletionContributor.java index f18e7debb496..fa2bf7eb1d16 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PyDocstringCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PyDocstringCompletionContributor.java @@ -28,10 +28,10 @@ import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ProcessingContext; import com.jetbrains.python.documentation.docstrings.DocStringParameterReference; +import com.jetbrains.python.documentation.docstrings.DocStringTagCompletionContributor; import com.jetbrains.python.documentation.docstrings.DocStringTypeReference; import com.jetbrains.python.psi.PyDocStringOwner; import com.jetbrains.python.psi.PyNamedParameter; -import com.jetbrains.python.psi.PyStringLiteralExpression; import com.jetbrains.python.refactoring.PyRefactoringUtil; import org.jetbrains.annotations.NotNull; @@ -47,7 +47,7 @@ import static com.intellij.patterns.StandardPatterns.or; public class PyDocstringCompletionContributor extends CompletionContributor { public PyDocstringCompletionContributor() { extend(CompletionType.BASIC, - or(psiElement().inside(PyStringLiteralExpression.class), psiComment()), + or(psiElement().withParent(DocStringTagCompletionContributor.DOCSTRING_PATTERN), psiComment()), new IdentifierCompletionProvider()); } diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java index d1e4a81efc9c..ff500a61e5b4 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java @@ -419,7 +419,8 @@ public class PyKeywordCompletionContributor extends CompletionContributor { .andNot(IN_PARAM_LIST) .andNot(IN_ARG_LIST) .andNot(BEFORE_COND) - .andNot(AFTER_QUALIFIER); + .andNot(AFTER_QUALIFIER) + .andNot(IN_STRING_LITERAL); extend( CompletionType.BASIC, @@ -609,6 +610,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor { .and(NOT_PARAMETER_OR_DEFAULT_VALUE) .andNot(AFTER_QUALIFIER) .andNot(IN_FUNCTION_HEADER) + .andNot(IN_STRING_LITERAL) , new PyKeywordCompletionProvider(TailType.NONE, PyNames.TRUE, PyNames.FALSE, PyNames.NONE)); extend(CompletionType.BASIC, @@ -708,7 +710,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor { psiElement() .inside(false, psiElement(PyAugAssignmentStatement.class), psiElement(PyTargetExpression.class)) .afterLeaf(psiElement().withElementType(PyTokenTypes.AUG_ASSIGN_OPERATIONS)), - psiElement().inside(true, psiElement(PyParenthesizedExpression.class))), + psiElement().inside(true, psiElement(PyParenthesizedExpression.class))).andNot(IN_STRING_LITERAL), new PyKeywordCompletionProvider(PyNames.YIELD)); } @@ -758,7 +760,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor { psiElement() .withLanguage(PythonLanguage.getInstance()) .and(psiElement()).afterLeaf(psiElement().afterLeaf(PyNames.FOR)), - new PyKeywordCompletionProvider("in")); + new PyKeywordCompletionProvider(PyNames.IN)); } diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyStringFormatCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyStringFormatCompletionContributor.java index cd86794044da..718c1ef2e28c 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PyStringFormatCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PyStringFormatCompletionContributor.java @@ -17,38 +17,205 @@ package com.jetbrains.python.codeInsight.completion; import com.intellij.codeInsight.completion.*; -import com.intellij.codeInsight.lookup.AutoCompletionPolicy; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.patterns.PatternCondition; +import com.intellij.patterns.PsiElementPattern; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.ProcessingContext; +import com.jetbrains.python.PyNames; import com.jetbrains.python.inspections.PyStringFormatParser; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.impl.PyPsiUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import static com.intellij.patterns.PlatformPatterns.psiElement; import static com.intellij.patterns.StandardPatterns.or; +import static java.util.Arrays.asList; public class PyStringFormatCompletionContributor extends CompletionContributor { + private static final String DICT_NAME = "dict"; + + private static final PatternCondition FORMAT_CALL_PATTERN_CONDITION = + new PatternCondition("isFormatFunction") { + + @Override + public boolean accepts(@NotNull PyReferenceExpression expression, ProcessingContext context) { + String expressionName = expression.getName(); + return expressionName != null && expressionName.equals(PyNames.FORMAT); + } + }; + + private static final PatternCondition DICT_CALL_PATTERN_CONDITION = + new PatternCondition("isDictCall") { + + @Override + public boolean accepts(@NotNull PyReferenceExpression expression, ProcessingContext context) { + String expressionName = expression.getName(); + return expressionName != null && expressionName.equals(DICT_NAME); + } + }; + + private static final PsiElementPattern.Capture FORMAT_STRING_CAPTURE = + psiElement(PyStringLiteralExpression.class) + .withParent(psiElement(PyReferenceExpression.class).with(FORMAT_CALL_PATTERN_CONDITION)) + .withSuperParent(2, PyCallExpression.class); + + private static final PsiElementPattern.Capture PERCENT_STRING_CAPTURE = + psiElement(PyStringLiteralExpression.class).beforeLeaf(psiElement().withText("%")).withParent(PyBinaryExpression.class); + + + @Nullable private static final PatternCondition PERCENT_BINARY_EXPRESSION_PATTERN = + new PatternCondition("isBinaryFormatExpression") { + @Override + public boolean accepts(@NotNull PyBinaryExpression expression, ProcessingContext context) { + return expression.isOperator("%"); + } + }; + + private static final PsiElementPattern.Capture DICT_FUNCTION_KEYWORD_ARGUMENT_CAPTURE = + (psiElement(PyKeywordArgument.class)) + .withSuperParent(3, + psiElement(PyBinaryExpression.class) + .withChild(psiElement(PyCallExpression.class) + .withChild(psiElement(PyReferenceExpression.class) + .with(DICT_CALL_PATTERN_CONDITION))) + .with(PERCENT_BINARY_EXPRESSION_PATTERN)); + + private static final PsiElementPattern.Capture DICT_FUNCTION_REFERENCE_ARGUMENT_CAPTURE = + (psiElement(PyReferenceExpression.class)) + .withSuperParent(3, + psiElement(PyBinaryExpression.class) + .withChild(psiElement(PyCallExpression.class) + .withChild(psiElement(PyReferenceExpression.class) + .with(DICT_CALL_PATTERN_CONDITION))) + .with(PERCENT_BINARY_EXPRESSION_PATTERN)); + + private static final PsiElementPattern.Capture FORMAT_FUNCTION_ARGUMENT_CAPTURE = + psiElement(PyKeywordArgument.class) + .withSuperParent(2, psiElement(PyCallExpression.class) + .withChild(psiElement(PyReferenceExpression.class).with(FORMAT_CALL_PATTERN_CONDITION))); + + // to provide completion for: "{foo}".format(fo) + private static final PsiElementPattern.Capture FORMAT_FUNCTION_REFERENCE_ARGUMENT_CAPTURE = + psiElement(PyReferenceExpression.class) + .withSuperParent(2, psiElement(PyCallExpression.class) + .withChild(psiElement(PyReferenceExpression.class).with(FORMAT_CALL_PATTERN_CONDITION))); + + private static final PsiElementPattern.Capture DICT_LITERAL_STRING_KEY_CAPTURE = + psiElement(PyStringLiteralExpression.class) + .withParent(or(psiElement(PyKeyValueExpression.class) + .withParent(psiElement(PyDictLiteralExpression.class) + .withParent(psiElement(PyBinaryExpression.class).with(PERCENT_BINARY_EXPRESSION_PATTERN))), + psiElement(PyDictLiteralExpression.class) + .withParent(psiElement(PyBinaryExpression.class).with(PERCENT_BINARY_EXPRESSION_PATTERN)))); + + // to provide completion for: "%(foo)s % {"f"} + private static final PsiElementPattern.Capture SET_LITERAL_STRING_KEY_CAPTURE = + psiElement(PyStringLiteralExpression.class) + .withParent(psiElement(PySetLiteralExpression.class).withParent(psiElement(PyBinaryExpression.class) + .with(PERCENT_BINARY_EXPRESSION_PATTERN))); + public PyStringFormatCompletionContributor() { extend( CompletionType.BASIC, - or(psiElement().inside(PyArgumentList - .class), psiElement().inside(PyStringLiteralExpression.class)), - new FormattedStringCompletionProvider() + or( + psiElement().inside(PERCENT_STRING_CAPTURE), + psiElement().inside(FORMAT_STRING_CAPTURE)), + new StringFormatCompletionProvider() + ); + + extend( + CompletionType.BASIC, + or(psiElement().inside(DICT_LITERAL_STRING_KEY_CAPTURE), + psiElement().inside(DICT_FUNCTION_KEYWORD_ARGUMENT_CAPTURE), + psiElement().inside(DICT_FUNCTION_REFERENCE_ARGUMENT_CAPTURE), + psiElement().inside(SET_LITERAL_STRING_KEY_CAPTURE), + psiElement().inside(FORMAT_FUNCTION_ARGUMENT_CAPTURE), + psiElement().inside(FORMAT_FUNCTION_REFERENCE_ARGUMENT_CAPTURE) + ), + new StringFormatArgumentsCompletionProvider() ); } + private static class StringFormatArgumentsCompletionProvider extends CompletionProvider { - private static class FormattedStringCompletionProvider extends CompletionProvider { + @Override + protected void addCompletions(@NotNull CompletionParameters parameters, + ProcessingContext context, + @NotNull CompletionResultSet result) { + final PsiElement original = parameters.getOriginalPosition(); + if (original != null) { + result = result.withPrefixMatcher(getPrefix(parameters.getOffset(), parameters.getOriginalFile())); + final PsiElement parent = original.getParent(); + if (parent.getParent() instanceof PyKeyValueExpression || parent instanceof PyStringLiteralExpression) { + final PyBinaryExpression binExpr = PsiTreeUtil.getParentOfType(parent, PyBinaryExpression.class); + if (binExpr != null) { + final PyStringLiteralExpression strExpr = PyUtil.as(binExpr.getLeftExpression(), PyStringLiteralExpression.class); + if (strExpr != null) { + result.addAllElements(getPercentLookupBuilders(strExpr)); + } + } + } + else if (PyUtil.instanceOf(parent, PyKeywordArgument.class, PyReferenceExpression.class)) { + result.addAllElements(getElementsFromString(PsiTreeUtil.getParentOfType(original, PyArgumentList.class))); + } + } + } + + @NotNull + private static List getElementsFromString(@Nullable final PyArgumentList argumentList) { + if (argumentList != null) { + final PyReferenceExpression refExpr = PsiTreeUtil.getPrevSiblingOfType(argumentList, PyReferenceExpression.class); + final PyStringLiteralExpression strExpr = PsiTreeUtil.getChildOfType(refExpr, PyStringLiteralExpression.class); + if (strExpr != null) { + return getFormatLookupBuilders(strExpr); + } + else { + final PyBinaryExpression binExpr = PsiTreeUtil.getParentOfType(refExpr, PyBinaryExpression.class); + if (binExpr != null) { + final PyStringLiteralExpression stringLiteralExpr = PyUtil.as(binExpr.getLeftExpression(), PyStringLiteralExpression.class); + if (stringLiteralExpr != null) { + return getPercentLookupBuilders(stringLiteralExpr); + } + } + } + } + return Collections.emptyList(); + } + + @NotNull + private static List getFormatLookupBuilders(@NotNull final PyStringLiteralExpression expression) { + final Map chunks = PyStringFormatParser.getKeywordSubstitutions( + PyStringFormatParser.filterSubstitutions(PyStringFormatParser.parseNewStyleFormat(expression.getStringValue()))); + return getLookupBuilders(chunks); + } + + private static List getPercentLookupBuilders(@NotNull final PyStringLiteralExpression expression) { + final Map chunks = PyStringFormatParser.getKeywordSubstitutions( + PyStringFormatParser.filterSubstitutions(PyStringFormatParser.parsePercentFormat(expression.getStringValue()))); + return getLookupBuilders(chunks); + } + + @NotNull + private static List getLookupBuilders(@NotNull final Map chunks) { + return chunks.keySet().stream() + .map(PyStringFormatCompletionContributor::createLookUpElement) + .collect(Collectors.toList()); + } + } + + private static class StringFormatCompletionProvider extends CompletionProvider { @Override protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @@ -56,63 +223,111 @@ public class PyStringFormatCompletionContributor extends CompletionContributor { final PsiElement original = parameters.getOriginalPosition(); if (original != null) { final PsiElement parent = original.getParent(); + result = result.withPrefixMatcher(getPrefix(parameters.getOffset(), parent.getContainingFile())); if (parent instanceof PyStringLiteralExpression) { - final int stringOffset = parameters.getOffset() - parameters.getPosition().getTextRange().getStartOffset(); - if (isInsideSubstitutionChunk((PyStringLiteralExpression)parent, - stringOffset)) { - final PyExpression[] arguments = getFormatFunctionKeyWordArguments(original); - for (PyExpression argument : arguments) { - result = result.withPrefixMatcher(getPrefix(parameters.getOffset(), argument.getContainingFile())); - addKeysFromStarArgument(result, argument); - addKeyWordArgument(result, argument); - } - } - } - else if (PyUtil.instanceOf(parent, PyKeywordArgument.class, PyReferenceExpression.class)) { - final PyArgumentList argumentList = PsiTreeUtil.getParentOfType(original, PyArgumentList.class); - result = result.withPrefixMatcher(getPrefix(parameters.getOffset(), parent.getContainingFile())); - addElementsFromFormattedString(result, argumentList); + result.addAllElements(addCompletionsForSubstitutions(parameters, original, (PyStringLiteralExpression)parent)); } } } - private static boolean isInsideSubstitutionChunk(@NotNull final PyStringLiteralExpression expression, final int offset) { - final List substitutions = PyStringFormatParser.filterSubstitutions( - PyStringFormatParser.parseNewStyleFormat(expression.getStringValue())); - for (PyStringFormatParser.SubstitutionChunk substitution: substitutions) { - if (offset >= substitution.getStartIndex() && offset <= substitution.getEndIndex()) { - return true; - } - } - return false; - } - @NotNull - private static PyExpression[] getFormatFunctionKeyWordArguments(final PsiElement original) { - final PsiElement pyReferenceExpression = PsiTreeUtil.getParentOfType(original, PyReferenceExpression.class); - final PyArgumentList argumentList = PsiTreeUtil.getNextSiblingOfType(pyReferenceExpression, PyArgumentList.class); - if (argumentList != null) { - return argumentList.getArguments(); - } - return PyExpression.EMPTY_ARRAY; - } + private static List addCompletionsForSubstitutions(@NotNull final CompletionParameters parameters, + @NotNull final PsiElement original, + @NotNull final PyStringLiteralExpression stringExpression) { + final int stringOffset = getCaretStartOffsetInsideString(parameters, stringExpression); - private static void addKeysFromStarArgument(@NotNull final CompletionResultSet result, @NotNull final PyExpression arg) { - if (arg instanceof PyStarArgument) { - final PyDictLiteralExpression dict = ObjectUtils.chooseNotNull(PsiTreeUtil.getChildOfType(arg, PyDictLiteralExpression.class), - getDictFromReference(arg)); - if (dict != null) { - for (PyKeyValueExpression keyValue: dict.getElements()) { - if (keyValue.getKey() instanceof PyStringLiteralExpression) { - final String key = ((PyStringLiteralExpression) keyValue.getKey()).getStringValue(); - result.addElement(createLookUpElement(key)); + if (isInsideFormatSubstitutionChunk(stringExpression, stringOffset)) { + final PyExpression[] arguments = getFormatFunctionKeyWordArguments(original); + final ArrayList elements = new ArrayList<>(); + for (PyExpression argument : arguments) { + if (argument instanceof PyKeywordArgument) { + elements.add(getKeywordArgument((PyKeywordArgument)argument)); + } + else if (argument instanceof PyStarArgument) { + elements.addAll(getKeysFromStarArgument((PyStarArgument)argument)); + } + } + return elements; + } + + if (isInsidePercentSubstitutionChunk(stringExpression, stringOffset)) { + final PyBinaryExpression binExpr = PyUtil.as(PsiTreeUtil.getParentOfType(stringExpression, PyBinaryExpression.class), + PyBinaryExpression.class); + if (binExpr != null) { + final PyExpression rightExpr = PyPsiUtils.flattenParens(binExpr.getRightExpression()); + + final PyDictLiteralExpression dict = PyUtil.as(rightExpr, PyDictLiteralExpression.class); + if (dict != null) { + return getElementsFromDict(dict); + } + + final PyCallExpression callExpression = PyUtil.as(rightExpr, PyCallExpression.class); + if (callExpression != null) { + final PyExpression callee = callExpression.getCallee(); + if (callee != null && callee.getName() != null && callee.getName().equals(DICT_NAME)) { + final PyExpression[] arguments = callExpression.getArguments(); + return asList(arguments).stream() + .filter(a -> a instanceof PyKeywordArgument) + .map(a -> getKeywordArgument((PyKeywordArgument)a)) + .filter(e -> e != null) + .collect(Collectors.toList()); } } } } + return Collections.emptyList(); } + private static int getCaretStartOffsetInsideString(@NotNull final CompletionParameters parameters, + @NotNull final PyStringLiteralExpression parent) { + final int caretAbsoluteOffset = parameters.getOffset(); + final int stringExprStartOffset = parameters.getPosition().getTextRange().getStartOffset(); + final int stringValueStartOffset = parent.getStringValueTextRange().getStartOffset(); + return caretAbsoluteOffset - stringExprStartOffset - stringValueStartOffset; + } + + private static boolean isInsideFormatSubstitutionChunk(@NotNull final PyStringLiteralExpression expression, final int offset) { + List substitutions = PyStringFormatParser.filterSubstitutions( + PyStringFormatParser.parseNewStyleFormat(expression.getStringValue())); + return isInsideSubstitutionChunk(offset, substitutions); + } + + private static boolean isInsidePercentSubstitutionChunk(@NotNull final PyStringLiteralExpression expression, final int offset) { + List substitutions = PyStringFormatParser.filterSubstitutions( + PyStringFormatParser.parsePercentFormat(expression.getStringValue())); + return isInsideSubstitutionChunk(offset, substitutions); + } + + private static boolean isInsideSubstitutionChunk(int offset, @NotNull List substitutions) { + return substitutions.stream().anyMatch(s -> offset >= s.getStartIndex() && offset <= s.getEndIndex()); + } + + @NotNull + private static PyExpression[] getFormatFunctionKeyWordArguments(@NotNull final PsiElement original) { + final PsiElement pyReferenceExpression = PsiTreeUtil.getParentOfType(original, PyReferenceExpression.class); + final PyArgumentList argumentList = PsiTreeUtil.getNextSiblingOfType(pyReferenceExpression, PyArgumentList.class); + return argumentList != null ? argumentList.getArguments() : PyExpression.EMPTY_ARRAY; + } + + @NotNull + private static List getKeysFromStarArgument(@NotNull final PyStarArgument arg) { + final PyDictLiteralExpression dict = ObjectUtils.chooseNotNull(PsiTreeUtil.getChildOfType(arg, PyDictLiteralExpression.class), + getDictFromReference(arg)); + + return dict != null ? getElementsFromDict(dict) : Collections.emptyList(); + } + + @NotNull + private static List getElementsFromDict(@NotNull final PyDictLiteralExpression dict) { + return asList(dict.getElements()).stream() + .map(e -> PyUtil.as(e.getKey(), PyStringLiteralExpression.class)) + .filter(k-> k != null) + .map(k -> createLookUpElement(k.getStringValue())) + .collect(Collectors.toList()); + } + + @Nullable private static PyDictLiteralExpression getDictFromReference(@NotNull final PyExpression arg) { final PyReferenceExpression referenceExpression = PsiTreeUtil.getChildOfType(arg, PyReferenceExpression.class); if (referenceExpression != null) { @@ -125,58 +340,31 @@ public class PyStringFormatCompletionContributor extends CompletionContributor { return null; } - private static void addKeyWordArgument(@NotNull final CompletionResultSet result, @NotNull final PyExpression arg) { - if (arg instanceof PyKeywordArgument) { - final String keyword = ((PyKeywordArgument)arg).getKeyword(); - if (keyword!= null) { - result.addElement(createLookUpElement(keyword)); - } - } + @Nullable + private static LookupElement getKeywordArgument(@NotNull final PyKeywordArgument arg) { + final String keyword = arg.getKeyword(); + return keyword != null ? createLookUpElement(keyword) : null; } - - @NotNull - private static LookupElement createLookUpElement(@NotNull final String element) { - return LookupElementBuilder - .create(element) - .withTypeText("arg") - .withAutoCompletionPolicy(AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE); - } - - private static void addElementsFromFormattedString(@NotNull final CompletionResultSet result, - @Nullable final PyArgumentList argumentList) { - if (argumentList != null) { - final PyReferenceExpression pyReferenceExpression = PsiTreeUtil.getPrevSiblingOfType(argumentList, PyReferenceExpression.class); - final PyStringLiteralExpression formattedString = PsiTreeUtil.getChildOfType(pyReferenceExpression, PyStringLiteralExpression.class); - if (formattedString != null) { - result.addAllElements(getLookupBuilders(formattedString)); - } - } - } - - @NotNull - private static List getLookupBuilders(@NotNull final PyStringLiteralExpression literalExpression) { - final Map chunks = PyStringFormatParser.getKeywordSubstitutions( - PyStringFormatParser.filterSubstitutions(PyStringFormatParser.parseNewStyleFormat(literalExpression.getStringValue()))); - final List keys = new ArrayList<>(); - for (String chunk: chunks.keySet()) { - keys.add(createLookUpElement(chunk)); - } - return keys; - } - } + @NotNull + private static LookupElement createLookUpElement(@NotNull final String element) { + return LookupElementBuilder + .create(element) + .withTypeText("arg"); + } + + @NotNull private static String getPrefix(int offset, @NotNull final PsiFile file) { if (offset > 0) { offset--; } final String text = file.getText(); final StringBuilder prefixBuilder = new StringBuilder(); - while(offset > 0 && Character.isLetterOrDigit(text.charAt(offset))) { + while (offset > 0 && Character.isLetterOrDigit(text.charAt(offset))) { prefixBuilder.insert(0, text.charAt(offset)); offset--; } return prefixBuilder.toString(); } - } diff --git a/python/src/com/jetbrains/python/console/PyConsoleEnterHandler.kt b/python/src/com/jetbrains/python/console/PyConsoleEnterHandler.kt index be814fd57e35..75dce0ce2116 100644 --- a/python/src/com/jetbrains/python/console/PyConsoleEnterHandler.kt +++ b/python/src/com/jetbrains/python/console/PyConsoleEnterHandler.kt @@ -27,10 +27,9 @@ import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiWhiteSpace -import com.intellij.psi.impl.source.codeStyle.IndentHelperImpl import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.DocumentUtil import com.jetbrains.python.PyTokenTypes -import com.jetbrains.python.PythonFileType import com.jetbrains.python.psi.PyStatementListContainer import com.jetbrains.python.psi.PyStringLiteralExpression import com.jetbrains.python.psi.impl.PyPsiUtils @@ -40,12 +39,15 @@ import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl class PyConsoleEnterHandler { fun handleEnterPressed(editor: EditorEx): Boolean { val project = editor.project ?: throw IllegalArgumentException() - if (editor.document.lineCount != 0) { // move to end of line + if (editor.document.lineCount > 0) { // move to end of line editor.selectionModel.removeSelection() val caretPosition = editor.caretModel.logicalPosition val lineEndOffset = editor.document.getLineEndOffset(caretPosition.line) editor.caretModel.moveToOffset(lineEndOffset) } + else { + return true; + } val psiMgr = PsiDocumentManager.getInstance(project) psiMgr.commitDocument(editor.document) @@ -64,24 +66,19 @@ class PyConsoleEnterHandler { } }.execute() + val firstLine = getLineAtOffset(editor.document, DocumentUtil.getFirstNonSpaceCharOffset(editor.document, 0)) + val isCellMagic = firstLine.trim().startsWith("%%") && !firstLine.trimEnd().endsWith("?") + val isMultiLineCommand = PsiTreeUtil.getParentOfType(atElement, PyStatementListContainer::class.java) != null || isCellMagic + + val hasCompleteStatement = atElement != null && !insideDocString && checkComplete(atElement) val prevLine = getLineAtOffset(editor.document, caretOffset) - val isCellMagic = prevLine.trim().startsWith("%%") && !prevLine.trimEnd().endsWith("?") - val isCellHelp = prevLine.trim().startsWith("%%") && prevLine.trimEnd().endsWith("?") - val isLineCellMagic = prevLine.trim().startsWith("%") - val hasCompleteStatement = atElement != null && !insideDocString && !isCellMagic && - (isCellHelp || isLineCellMagic || checkComplete(atElement)) - val currentLine = getLineAtOffset(editor.document, editor.expectedCaretOffset) - val indent = IndentHelperImpl.getIndent(project, PythonFileType.INSTANCE, currentLine, false) - - return indent == 0 || (hasCompleteStatement && prevLine.isBlank()) + return hasCompleteStatement && ((isMultiLineCommand && prevLine.isBlank()) || (!isMultiLineCommand)) } private fun isElementInsideDocString(atElement: PsiElement, caretOffset: Int): Boolean { - return (atElement.context is PyStringLiteralExpression && - (PyTokenTypes.TRIPLE_NODES.contains(atElement.node.elementType) - || atElement.node.elementType === PyTokenTypes.DOCSTRING) - && (atElement.textRange.endOffset > caretOffset || !isCompletDocString(atElement.text))) + return atElement.context is PyStringLiteralExpression && PyTokenTypes.TRIPLE_NODES.contains(atElement.node.elementType) + && (atElement.textRange.endOffset > caretOffset || !isCompleteDocString(atElement.text)) } private fun checkComplete(el: PsiElement): Boolean { @@ -89,8 +86,9 @@ class PyConsoleEnterHandler { if (compoundStatement != null) { return compoundStatement.statementList.statements.size != 0 } + if (el.parent == null) return false val topLevel = PyPsiUtils.getParentRightBefore(el, el.containingFile) - return topLevel != null && PsiTreeUtil.hasErrorElements(topLevel) + return topLevel != null && !PsiTreeUtil.hasErrorElements(topLevel) } private fun findFirstNoneSpaceElement(psiFile: PsiFile, offset: Int): PsiElement? { @@ -110,7 +108,7 @@ class PyConsoleEnterHandler { return doc.getText(TextRange(start, end)) } - private fun isCompletDocString(str: String): Boolean { + private fun isCompleteDocString(str: String): Boolean { val prefixLen = PyStringLiteralExpressionImpl.getPrefixLength(str) val text = str.substring(prefixLen) for (token in arrayOf("\"\"\"", "'''")) { diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java b/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java index 578323d58e0a..28596f9af9a8 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java @@ -63,11 +63,15 @@ import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Couple; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.ToolWindow; import com.intellij.psi.PsiFile; import com.intellij.remote.RemoteProcess; import com.intellij.remote.Tunnelable; @@ -107,8 +111,10 @@ import java.awt.event.KeyEvent; import java.io.File; import java.io.IOException; import java.net.ServerSocket; -import java.util.*; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Scanner; import java.util.stream.Collectors; import static com.intellij.execution.runners.AbstractConsoleRunnerWithHistory.registerActionShortcuts; @@ -317,10 +323,9 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { private void showContentDescriptor(RunContentDescriptor contentDescriptor) { - PythonConsoleToolWindow toolWindow = PythonConsoleToolWindow.getInstance(myProject); - if (toolWindow != null) { - toolWindow - .init(PythonConsoleToolWindow.getToolWindow(myProject), contentDescriptor); + ToolWindow toolwindow = PythonConsoleToolWindow.getToolWindow(myProject); + if (toolwindow != null) { + PythonConsoleToolWindow.getInstance(myProject).init(toolwindow, contentDescriptor); } else { ExecutionManager diff --git a/python/testData/completion/formatStringWithFormatModifier.after.py b/python/testData/completion/formatStringWithFormatModifier.after.py new file mode 100644 index 000000000000..fd3cbf8745f0 --- /dev/null +++ b/python/testData/completion/formatStringWithFormatModifier.after.py @@ -0,0 +1 @@ +r"{completed}".format(completed="hood") \ No newline at end of file diff --git a/python/testData/completion/formatStringWithFormatModifier.py b/python/testData/completion/formatStringWithFormatModifier.py new file mode 100644 index 000000000000..326bd387e8ec --- /dev/null +++ b/python/testData/completion/formatStringWithFormatModifier.py @@ -0,0 +1 @@ +r"{compl}".format(completed="hood") \ No newline at end of file diff --git a/python/testData/completion/percentStringDictCallStringKey.after.py b/python/testData/completion/percentStringDictCallStringKey.after.py new file mode 100644 index 000000000000..b511e971f8f9 --- /dev/null +++ b/python/testData/completion/percentStringDictCallStringKey.after.py @@ -0,0 +1 @@ +"%(completion)s" % dict(completion) \ No newline at end of file diff --git a/python/testData/completion/percentStringDictCallStringKey.py b/python/testData/completion/percentStringDictCallStringKey.py new file mode 100644 index 000000000000..85f51a432740 --- /dev/null +++ b/python/testData/completion/percentStringDictCallStringKey.py @@ -0,0 +1 @@ +"%(completion)s" % dict(complet) \ No newline at end of file diff --git a/python/testData/completion/percentStringDictFuncKeys.py b/python/testData/completion/percentStringDictFuncKeys.py new file mode 100644 index 000000000000..779cf0f0de4d --- /dev/null +++ b/python/testData/completion/percentStringDictFuncKeys.py @@ -0,0 +1 @@ +print("Other string %()d" % {str(4): int('4')}) \ No newline at end of file diff --git a/python/testData/completion/percentStringDictLiteralArgument.after.py b/python/testData/completion/percentStringDictLiteralArgument.after.py new file mode 100644 index 000000000000..d7e3feb45085 --- /dev/null +++ b/python/testData/completion/percentStringDictLiteralArgument.after.py @@ -0,0 +1 @@ +"format: %(fooo)s" % {"boo":1, "fooo"} \ No newline at end of file diff --git a/python/testData/completion/percentStringDictLiteralArgument.py b/python/testData/completion/percentStringDictLiteralArgument.py new file mode 100644 index 000000000000..de95e3756ebc --- /dev/null +++ b/python/testData/completion/percentStringDictLiteralArgument.py @@ -0,0 +1 @@ +"format: %(fooo)s" % {"boo":1, "foo"} \ No newline at end of file diff --git a/python/testData/completion/percentStringDictLiteralStringKey.after.py b/python/testData/completion/percentStringDictLiteralStringKey.after.py new file mode 100644 index 000000000000..a6b1a9f515a8 --- /dev/null +++ b/python/testData/completion/percentStringDictLiteralStringKey.after.py @@ -0,0 +1 @@ +"format: %(fooo)s" % {"fooo"} \ No newline at end of file diff --git a/python/testData/completion/percentStringDictLiteralStringKey.py b/python/testData/completion/percentStringDictLiteralStringKey.py new file mode 100644 index 000000000000..cdb848d3a4d1 --- /dev/null +++ b/python/testData/completion/percentStringDictLiteralStringKey.py @@ -0,0 +1 @@ +"format: %(fooo)s" % {"fo"} \ No newline at end of file diff --git a/python/testData/completion/percentStringDictRefKeys.py b/python/testData/completion/percentStringDictRefKeys.py new file mode 100644 index 000000000000..5dc9af3f05cb --- /dev/null +++ b/python/testData/completion/percentStringDictRefKeys.py @@ -0,0 +1,3 @@ +f = "fst" +s1 = "snd" +print("first is %()s, second is %(snd)s" % {f: 1, s1: 2}) \ No newline at end of file diff --git a/python/testData/completion/percentStringDictWithDictLiteralArg.py b/python/testData/completion/percentStringDictWithDictLiteralArg.py new file mode 100644 index 000000000000..82be749c8908 --- /dev/null +++ b/python/testData/completion/percentStringDictWithDictLiteralArg.py @@ -0,0 +1 @@ +print("Other string %()d" % dict({'three': 3, 'one': 1, 'two': 2})) \ No newline at end of file diff --git a/python/testData/completion/percentStringDictWithListArg.py b/python/testData/completion/percentStringDictWithListArg.py new file mode 100644 index 000000000000..ab917d16be2f --- /dev/null +++ b/python/testData/completion/percentStringDictWithListArg.py @@ -0,0 +1 @@ +print("Other string %()d" % dict([('two', 2), ('one', 1), ('three', 3)])) \ No newline at end of file diff --git a/python/testData/completion/percentStringDictWithPackedDictLiteralArg.py b/python/testData/completion/percentStringDictWithPackedDictLiteralArg.py new file mode 100644 index 000000000000..8b798b097532 --- /dev/null +++ b/python/testData/completion/percentStringDictWithPackedDictLiteralArg.py @@ -0,0 +1,2 @@ +d = {'three': 3, 'one': 1, 'two': 2} +print("Other string %()d" % dict(**d)) \ No newline at end of file diff --git a/python/testData/completion/percentStringDictWithZipCall.py b/python/testData/completion/percentStringDictWithZipCall.py new file mode 100644 index 000000000000..81308afb3a3b --- /dev/null +++ b/python/testData/completion/percentStringDictWithZipCall.py @@ -0,0 +1 @@ +print("Other string %()d" % dict(zip(['one', 'two', 'three'], [1, 2, 3]))) \ No newline at end of file diff --git a/python/testData/completion/percentStringWithDictCallArg.after.py b/python/testData/completion/percentStringWithDictCallArg.after.py new file mode 100644 index 000000000000..1746bbfe255b --- /dev/null +++ b/python/testData/completion/percentStringWithDictCallArg.after.py @@ -0,0 +1 @@ +"to be %(completed)s" % dict(completed="smth") \ No newline at end of file diff --git a/python/testData/completion/percentStringWithDictCallArg.py b/python/testData/completion/percentStringWithDictCallArg.py new file mode 100644 index 000000000000..c5b1e67ec3c5 --- /dev/null +++ b/python/testData/completion/percentStringWithDictCallArg.py @@ -0,0 +1 @@ +"to be %(comple)s" % dict(completed="smth") \ No newline at end of file diff --git a/python/testData/completion/percentStringWithDictLiteralArg.after.py b/python/testData/completion/percentStringWithDictLiteralArg.after.py new file mode 100644 index 000000000000..0fc03b14c9c7 --- /dev/null +++ b/python/testData/completion/percentStringWithDictLiteralArg.after.py @@ -0,0 +1 @@ +"format: %(completion)s" % {"completion": "smth"} \ No newline at end of file diff --git a/python/testData/completion/percentStringWithDictLiteralArg.py b/python/testData/completion/percentStringWithDictLiteralArg.py new file mode 100644 index 000000000000..78d3719c68cf --- /dev/null +++ b/python/testData/completion/percentStringWithDictLiteralArg.py @@ -0,0 +1 @@ +"format: %(complet)s" % {"completion": "smth"} \ No newline at end of file diff --git a/python/testData/completion/percentStringWithModifiers.after.py b/python/testData/completion/percentStringWithModifiers.after.py new file mode 100644 index 000000000000..cf1d5fa339dd --- /dev/null +++ b/python/testData/completion/percentStringWithModifiers.after.py @@ -0,0 +1 @@ +r"%(completion)s" % dict(completion="smth") \ No newline at end of file diff --git a/python/testData/completion/percentStringWithModifiers.py b/python/testData/completion/percentStringWithModifiers.py new file mode 100644 index 000000000000..100deae1f4a6 --- /dev/null +++ b/python/testData/completion/percentStringWithModifiers.py @@ -0,0 +1 @@ +r"%(compl)s" % dict(completion="smth") \ No newline at end of file diff --git a/python/testData/completion/percentStringWithParenDictCallArg.after.py b/python/testData/completion/percentStringWithParenDictCallArg.after.py new file mode 100644 index 000000000000..281d52c5862c --- /dev/null +++ b/python/testData/completion/percentStringWithParenDictCallArg.after.py @@ -0,0 +1 @@ +"to be %(completion)s" % dict(completion="smth") \ No newline at end of file diff --git a/python/testData/completion/percentStringWithParenDictCallArg.py b/python/testData/completion/percentStringWithParenDictCallArg.py new file mode 100644 index 000000000000..81d8f5a4aabe --- /dev/null +++ b/python/testData/completion/percentStringWithParenDictCallArg.py @@ -0,0 +1 @@ +"to be %(complet)s" % dict(completion="smth") \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyConsoleEnterHandlerTest.kt b/python/testSrc/com/jetbrains/python/PyConsoleEnterHandlerTest.kt index 24d25db3a6d1..dfb851f2738d 100644 --- a/python/testSrc/com/jetbrains/python/PyConsoleEnterHandlerTest.kt +++ b/python/testSrc/com/jetbrains/python/PyConsoleEnterHandlerTest.kt @@ -50,8 +50,11 @@ class PyConsoleEnterHandlerTest : PyTestCase() { fun testTripleQuotes() { assertFalse(push("'''abs")) + } - + fun testSingleQuote() { + assertTrue(push("'a'")) + assertTrue(push("a = 'abc'")) } fun testSimpleSingleLine() { @@ -109,6 +112,15 @@ class PyConsoleEnterHandlerTest : PyTestCase() { } + fun testMultiLineIf() { + assertFalse(push("if True:")) + assertFalse(push("")) + assertFalse(push("")) + assertFalse(push("")) + assertFalse(push("\ta = 1")) + assertTrue(push("")) + } + override fun tearDown() { Disposer.dispose(testRootDisposable) super.tearDown() diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java index d64a6be42a1e..c36c0b839008 100644 --- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java @@ -864,31 +864,107 @@ public class PythonCompletionTest extends PyTestCase { doTest(); } - //PY-3077 + // PY-3077 public void testFormatString() { doTest(); } - //PY-3077 + // PY-3077 public void testFormatFuncArgument() { doTest(); } - //PY-3077 + // PY-3077 public void testFormatStringFromStarArg() { doTest(); } - //PY-3077 + // PY-3077 public void testFormatStringOutsideBraces() { doTest(); } - //PY-3077 + // PY-3077 public void testFormatStringFromRef() { doTest(); } + // PY-3077 + public void testFormatStringWithFormatModifier() { + doTest(); + } + + // PY-3077 + public void testPercentStringWithDictLiteralArg() { + doTest(); + } + + // PY-3077 + public void testPercentStringWithDictCallArg() { + doTest(); + } + + // PY-3077 + public void testPercentStringWithParenDictCallArg() { + doTest(); + } + + // PY-3077 + public void testPercentStringWithModifiers() { + doTest(); + } + + // PY-3077 + public void testPercentStringDictLiteralStringKey() { + doTest(); + } + + // PY-3077 + public void testPercentStringDictCallStringKey() { + doTest(); + } + + // PY-3077 + public void testPercentStringDictLiteralArgument() { + doTest(); + } + + // PY-19839 + public void testPercentStringDictRefKeys() { + final List variants = doTestByFile(); + assertNullOrEmpty(variants); + } + + // PY-19839 + public void testPercentStringDictFuncKeys() { + final List variants = doTestByFile(); + assertNullOrEmpty(variants); + } + + // PY-19839 + public void testPercentStringDictWithZipCall() { + final List variants = doTestByFile(); + assertNullOrEmpty(variants); + } + + // PY-19839 + public void testPercentStringDictWithListArg() { + final List variants = doTestByFile(); + assertNullOrEmpty(variants); + } + + // PY-19839 + public void testPercentStringDictWithDictLiteralArg() { + final List variants = doTestByFile(); + assertNullOrEmpty(variants); + } + + // PY-19839 + public void testPercentStringDictWithPackedDictLiteralArg() { + final List variants = doTestByFile(); + assertNullOrEmpty(variants); + } + // PY-17437 public void testStrFormat() { doTest(); diff --git a/resources-en/src/intentionDescriptions/InlineStreamMapAction/after.java.template b/resources-en/src/intentionDescriptions/InlineStreamMapAction/after.java.template new file mode 100644 index 000000000000..96a6374ab244 --- /dev/null +++ b/resources-en/src/intentionDescriptions/InlineStreamMapAction/after.java.template @@ -0,0 +1,7 @@ +import java.util.List; + +public class X { + boolean test(List list) { + return list.stream().anyMatch(s -> s.toLowerCase().equals("test")); + } +} \ No newline at end of file diff --git a/resources-en/src/intentionDescriptions/InlineStreamMapAction/before.java.template b/resources-en/src/intentionDescriptions/InlineStreamMapAction/before.java.template new file mode 100644 index 000000000000..7c507d8efd91 --- /dev/null +++ b/resources-en/src/intentionDescriptions/InlineStreamMapAction/before.java.template @@ -0,0 +1,7 @@ +import java.util.List; + +public class X { + boolean test(List list) { + return list.stream().map(s -> s.toLowerCase()).anyMatch(s -> s.equals("test")); + } +} \ No newline at end of file diff --git a/resources-en/src/intentionDescriptions/InlineStreamMapAction/description.html b/resources-en/src/intentionDescriptions/InlineStreamMapAction/description.html new file mode 100644 index 000000000000..60ad2cec8290 --- /dev/null +++ b/resources-en/src/intentionDescriptions/InlineStreamMapAction/description.html @@ -0,0 +1,7 @@ + + +This intention inlines Stream.map() and similar calls into the next stream operation when possible. + +As during normal variable inline this intention may change the code semantics if mapping result is used more than once and has side-effects. + + \ No newline at end of file diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 580077864f1d..d537318ea920 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -878,6 +878,10 @@ com.intellij.codeInsight.intention.impl.MergeFilterChainAction Java/Streams
+ + com.intellij.codeInsight.intention.impl.InlineStreamMapAction + Java/Streams + com.intellij.codeInsight.intention.impl.InvertIfConditionAction Java/Control Flow