diff --git a/.idea/libraries/xml_apis_ext.xml b/.idea/libraries/xml_apis_ext.xml deleted file mode 100644 index 368baaa64373..000000000000 --- a/.idea/libraries/xml_apis_ext.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/RegExpSupport/src/org/intellij/lang/regexp/inspection/SingleCharAlternationInspection.java b/RegExpSupport/src/org/intellij/lang/regexp/inspection/SingleCharAlternationInspection.java index ef981cea5c37..2027351f6fd1 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/inspection/SingleCharAlternationInspection.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/inspection/SingleCharAlternationInspection.java @@ -28,6 +28,8 @@ import org.intellij.lang.regexp.psi.*; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import java.util.stream.Stream; + /** * @author Bas Leijdekkers */ @@ -60,17 +62,19 @@ public class SingleCharAlternationInspection extends LocalInspectionTool { if (branches.length < 2) { return; } - for (RegExpBranch branch : branches) { - final RegExpAtom[] atoms = branch.getAtoms(); - if (atoms.length != 1 || !(atoms[0] instanceof RegExpChar)) { - return; - } + if (!Stream.of(branches).allMatch(SingleCharAlternationVisitor::isSingleChar)) { + return; } final String text = buildReplacementText(pattern); //noinspection DialogTitleCapitalization myHolder.registerProblem(pattern, "Single character alternation in RegExp", new SingleCharAlternationFix(text)); } + private static boolean isSingleChar(RegExpBranch branch) { + final RegExpAtom[] atoms = branch.getAtoms(); + return atoms.length == 1 && atoms[0] instanceof RegExpChar; + } + private static class SingleCharAlternationFix implements LocalQuickFix { private final String myText; diff --git a/bin/scripts/unix/idea.sh b/bin/scripts/unix/idea.sh index 9c3ce47141c7..7df94672fb65 100755 --- a/bin/scripts/unix/idea.sh +++ b/bin/scripts/unix/idea.sh @@ -158,9 +158,9 @@ VM_OPTIONS_FILE="" if [ -n "$@@product_uc@@_VM_OPTIONS" -a -r "$@@product_uc@@_VM_OPTIONS" ]; then # explicit VM_OPTIONS_FILE="$@@product_uc@@_VM_OPTIONS" -elif [ -r "$HOME/.@@system_selector@@/@@vm_options@@$BITS.vmoptions" ]; then +elif [ -r "$HOME/.@@system_selector@@/config/@@vm_options@@$BITS.vmoptions" ]; then # user-overridden - VM_OPTIONS_FILE="$HOME/.@@system_selector@@/@@vm_options@@$BITS.vmoptions" + VM_OPTIONS_FILE="$HOME/.@@system_selector@@/config/@@vm_options@@$BITS.vmoptions" elif [ -r "$IDE_BIN_HOME/@@vm_options@@$BITS.vmoptions" ]; then # default, standard installation VM_OPTIONS_FILE="$IDE_BIN_HOME/@@vm_options@@$BITS.vmoptions" diff --git a/bin/scripts/win/idea.bat b/bin/scripts/win/idea.bat index 88ceb9b6d396..0069cef53a83 100644 --- a/bin/scripts/win/idea.bat +++ b/bin/scripts/win/idea.bat @@ -64,14 +64,14 @@ IF EXIST "%JRE%\lib\amd64" SET BITS=64 :: --------------------------------------------------------------------- IF NOT "%@@product_uc@@_PROPERTIES%" == "" SET IDE_PROPERTIES_PROPERTY="-Didea.properties.file=%@@product_uc@@_PROPERTIES%" -SET USER_VM_OPTIONS_FILE=%USERPROFILE%\.@@system_selector@@\@@vm_options@@.vmoptions +SET USER_VM_OPTIONS_FILE=%USERPROFILE%\.@@system_selector@@\config\@@vm_options@@.vmoptions SET VM_OPTIONS_FILE=%IDE_BIN_DIR%\@@vm_options@@.vmoptions IF EXIST "%IDE_BIN_DIR%\win\@@vm_options@@.vmoptions" SET VM_OPTIONS_FILE=%IDE_BIN_DIR%\win\@@vm_options@@.vmoptions IF EXIST %USER_VM_OPTIONS_FILE% SET VM_OPTIONS_FILE=%USER_VM_OPTIONS_FILE% IF NOT "%@@product_uc@@_VM_OPTIONS%" == "" SET VM_OPTIONS_FILE=%@@product_uc@@_VM_OPTIONS% SET ACC= -FOR /F "usebackq delims=" %%i IN ("%VM_OPTIONS_FILE%") DO CALL "%IDE_BIN_DIR%\append.bat" "%%i" +FOR /F "eol=# usebackq delims=" %%i IN ("%VM_OPTIONS_FILE%") DO CALL "%IDE_BIN_DIR%\append.bat" "%%i" IF EXIST "%VM_OPTIONS_FILE%" SET ACC=%ACC% -Djb.vmOptionsFile="%VM_OPTIONS_FILE%" SET COMMON_JVM_ARGS="-XX:ErrorFile=%USERPROFILE%\java_error_in_@@product_uc@@_%%p.log" "-XX:HeapDumpPath=%USERPROFILE%\java_error_in_@@product_uc@@.hprof" "-Xbootclasspath/a:%IDE_HOME%/lib/boot.jar" -Didea.paths.selector=@@system_selector@@ %IDE_PROPERTIES_PROPERTY% diff --git a/build.xml b/build.xml index 851b0e6ee3b0..399921036bb2 100644 --- a/build.xml +++ b/build.xml @@ -1,42 +1,16 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -44,6 +18,10 @@ + + + + @@ -52,15 +30,9 @@ - - - - - - - + @@ -68,7 +40,7 @@ - + @@ -78,6 +50,9 @@ + + + @@ -85,6 +60,4 @@ - - diff --git a/build/conf/nsis/idea.nsi b/build/conf/nsis/idea.nsi index 73605de3fa1c..ab804f300896 100644 --- a/build/conf/nsis/idea.nsi +++ b/build/conf/nsis/idea.nsi @@ -1110,6 +1110,7 @@ custom: complete: FileClose $3 ${UnStrRep} $2 $2 "/" "\" + DetailPrint "path to config/system: $2" FunctionEnd Function un.isIDEInUse diff --git a/build/dependencies/gradle.properties b/build/dependencies/gradle.properties index 093b51534f7a..6ce03251d82a 100644 --- a/build/dependencies/gradle.properties +++ b/build/dependencies/gradle.properties @@ -1,5 +1,4 @@ -#The file might be automatically updated. Comments and empty lines will be removed. -#Sat Apr 01 15:26:37 MSK 2017 -kotlinPluginBuild=1.1.1-release-IJ2017.1-1 +# The file might be automatically updated. Comments and empty lines will be removed. +kotlinPluginBuild=1.1.2-eap-69-IJ2017.2-1:EAP-1.1 jetSignBuild=42.30 -jdkBuild=u112b809.1 +jdkBuild=u152b829.1 diff --git a/build/dependencies/setupJbre.gradle b/build/dependencies/setupJbre.gradle index d3235c4595d9..e9501e9b04e5 100644 --- a/build/dependencies/setupJbre.gradle +++ b/build/dependencies/setupJbre.gradle @@ -47,7 +47,12 @@ jrePlatformsToDownload(targetOs).each { platform -> doFirst { exec { commandLine 'mkdir', '-p', outputDir } } commandLine 'tar', '-xpf', "${downloadOutputs.singleFile.absolutePath}", '--directory', outputDir if (platform != 'osx') { - doLast { exec { commandLine 'mv', "$outputDir/lib/tools.jar", "$outputDir/jre/lib/" } } + doLast { + exec { + commandLine 'mv', "$outputDir/lib/tools.jar", "$outputDir/jre/lib/" + ignoreExitValue = true + } + } } } } diff --git a/build/dependencies/setupKotlin.gradle b/build/dependencies/setupKotlin.gradle index 3f5eb2ef7dde..b21b7e402526 100644 --- a/build/dependencies/setupKotlin.gradle +++ b/build/dependencies/setupKotlin.gradle @@ -14,12 +14,8 @@ * limitations under the License. */ repositories { - maven { - url 'http://repo.labs.intellij.net/plugins.jetbrains.com' - } - maven { - url 'http://plugins.jetbrains.com/maven/' - } + maven { url 'http://repo.labs.intellij.net/plugins.jetbrains.com' } + maven { url 'http://plugins.jetbrains.com/maven/' } } configurations { @@ -30,18 +26,7 @@ dependencies { kotlinPlugin "com.jetbrains.plugins:org.jetbrains.kotlin:$kotlinPluginBuild@zip" } -task setupKotlinPlugin(dependsOn: configurations.kotlinPlugin) { - def kotlinPluginArchive = { configurations.kotlinPlugin.singleFile } - inputs.file(kotlinPluginArchive) - def outputDir = project.buildDir - outputs.dir("$outputDir/Kotlin") - - doFirst { logger.info("Setting up Kotlin") } - doLast { - logger.info("Unpack ${kotlinPluginArchive.call()} to $outputDir") - copy { - from zipTree(kotlinPluginArchive.call()) - into outputDir - } - } +task setupKotlinPlugin(dependsOn: configurations.kotlinPlugin, type: Sync) { + from zipTree(configurations.kotlinPlugin.singleFile) + into "${project.buildDir}/kotlin" } \ No newline at end of file diff --git a/build/gant.xml b/build/gant.xml index f5d132f4df94..fe1fb017fc4a 100644 --- a/build/gant.xml +++ b/build/gant.xml @@ -1,6 +1,5 @@ - @@ -21,16 +20,6 @@ - - - - - - - - - - @@ -49,8 +38,6 @@ - - diff --git a/build/groovy/org/jetbrains/intellij/build/BaseIdeaProperties.groovy b/build/groovy/org/jetbrains/intellij/build/BaseIdeaProperties.groovy index 82a78e76ae37..f4652f52fd13 100644 --- a/build/groovy/org/jetbrains/intellij/build/BaseIdeaProperties.groovy +++ b/build/groovy/org/jetbrains/intellij/build/BaseIdeaProperties.groovy @@ -117,7 +117,7 @@ abstract class BaseIdeaProperties extends ProductProperties { } } context.ant.copy(todir: "$targetDirectory/plugins/Kotlin") { - fileset(dir: "$context.paths.communityHome/build/dependencies/build/Kotlin") + fileset(dir: "$context.paths.kotlinHome") } context.ant.move(file: "$targetDirectory/lib/annotations-java8.jar", tofile: "$targetDirectory/redist/annotations-java8.jar") } diff --git a/build/groovy/org/jetbrains/intellij/build/IdeaCommunityBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/IdeaCommunityBuilder.groovy index 59a7623a7a55..936c9b8266a1 100644 --- a/build/groovy/org/jetbrains/intellij/build/IdeaCommunityBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/IdeaCommunityBuilder.groovy @@ -16,6 +16,8 @@ package org.jetbrains.intellij.build import org.codehaus.gant.GantBinding +import org.jetbrains.jps.gant.JpsGantTool + /** * @author nik */ @@ -25,6 +27,7 @@ class IdeaCommunityBuilder { IdeaCommunityBuilder(String home, GantBinding binding, BuildOptions options = new BuildOptions(), String projectHome = home) { this.binding = binding + binding.includeTool << JpsGantTool buildContext = BuildContext.createContext(binding.ant, binding.projectBuilder, binding.project, binding.global, home, projectHome, new IdeaCommunityProperties(home), ProprietaryBuildTools.DUMMY, options) diff --git a/build/groovy/org/jetbrains/intellij/build/IntelliJCoreArtifactsBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/IntelliJCoreArtifactsBuilder.groovy index 807dcf93ee33..26dd3a0822a4 100644 --- a/build/groovy/org/jetbrains/intellij/build/IntelliJCoreArtifactsBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/IntelliJCoreArtifactsBuilder.groovy @@ -106,7 +106,6 @@ class IntelliJCoreArtifactsBuilder { include(name: "imgscalr-lib-4.2.jar") include(name: "batik-all.jar") include(name: "xmlgraphics-commons-1.5.jar") - include(name: "xml-apis-ext.jar") } } buildContext.notifyArtifactBuilt(coreArtifactDir) diff --git a/build/scripts/dist.gant b/build/scripts/idea_community.gant similarity index 67% rename from build/scripts/dist.gant rename to build/scripts/idea_community.gant index 499e152e2a96..bd80d28014a3 100644 --- a/build/scripts/dist.gant +++ b/build/scripts/idea_community.gant @@ -13,44 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import org.jetbrains.intellij.build.BuildOptions import org.jetbrains.intellij.build.IdeaCommunityBuilder +import org.jetbrains.jps.idea.IdeaProjectLoader -import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome - -includeTargets << new File("${guessHome(this)}/build/scripts/utils.gant") - -requireProperty("out", "$home/out") - -// "out" has to be canonical, otherwise the ant build fails -// with mysterious errors -String out = new File(out).getCanonicalPath() +String home = IdeaProjectLoader.guessHome(this) target(compile: "Compile project") { - def options = new BuildOptions() - options.outputRootPath = out - new IdeaCommunityBuilder(home, binding, options).compileModules() + new IdeaCommunityBuilder(home, binding).compileModules() } target('default': 'The default target') { def options = new BuildOptions() - options.outputRootPath = out options.buildNumber = null //we cannot provide consistent build number for IDEA Community if it's built separately so use *.SNAPSHOT number to avoid confusion new IdeaCommunityBuilder(home, binding, options).buildDistributions() } -//todo[nik] do we really need this target? update.xml calls layout.gant directly -target('build-dist-jars' : 'Target to build jars from locally compiled classes') { - def options = new BuildOptions() - options.outputRootPath = out - options.useCompiledClassesFromProjectOutput = true - new IdeaCommunityBuilder(home, binding, options).buildDistJars() -} - target('build-intellij-core' : 'Build intellij-core.zip') { def options = new BuildOptions() - options.outputRootPath = out new IdeaCommunityBuilder(home, binding, options).buildIntelliJCore() } @@ -62,4 +42,14 @@ target('update-from-sources': 'Update locally installed distribution from compil //when IDEA CE is updated from IDEA UE sources project should be loaded from IDEA UE directory String projectHome = isDefined("devIdeaHome") ? devIdeaHome : home new IdeaCommunityBuilder(home, binding, options, projectHome).buildUnpackedDistribution(deploy) -} \ No newline at end of file +} + +private boolean isDefined(String key) { + try { + this[key] + return true + } + catch (MissingPropertyException ignored) { + return false + } +} diff --git a/build/scripts/tests_in_community.gant b/build/scripts/tests_in_community.gant index bdbf7c1e5c28..9c751ce28e61 100644 --- a/build/scripts/tests_in_community.gant +++ b/build/scripts/tests_in_community.gant @@ -17,6 +17,10 @@ import org.jetbrains.intellij.build.TestingTasks import org.jetbrains.intellij.build.impl.CompilationContextImpl import org.jetbrains.jps.idea.IdeaProjectLoader +/** + * Compiles the sources and runs tests from 'community' project. Look at org.jetbrains.intellij.build.TestingOptions to see which options are + * supported. + */ target("default": "Run tests") { String home = IdeaProjectLoader.guessHome(this) String outputDir = "$home/out/tests" diff --git a/build/scripts/utils.gant b/build/scripts/utils.gant index 974307edc841..800bb656f7b1 100644 --- a/build/scripts/utils.gant +++ b/build/scripts/utils.gant @@ -105,9 +105,9 @@ binding.setVariable("loadProject", { defineJdk("1.8", setupJdkPath("jdk8Home", "$home/build/jdk/1.8", "JDK_18_x64")) setupKotlin() - def bundledKotlinPath = "$home/build/dependencies/build/Kotlin/kotlinc" + def bundledKotlinPath = "$home/build/dependencies/build/kotlin/Kotlin/kotlinc" if (!new File(bundledKotlinPath, "lib/kotlin-runtime.jar").exists()) { - bundledKotlinPath = "$home/community/build/dependencies/build/Kotlin/kotlinc" + bundledKotlinPath = "$home/community/build/dependencies/build/kotlin/Kotlin/kotlinc" } if (!new File(bundledKotlinPath, "lib/kotlin-runtime.jar").exists()) { projectBuilder.error("Could not find Kotlin runtime at $bundledKotlinPath/lib/kotlin-runtime.jar: run `./gradlew setupKotlin` in dependencies module to download Kotlin JARs") @@ -150,16 +150,13 @@ private void setupKotlin() { } private boolean ensureKotlinCompilerAddedToClassPath() { - try { - Class.forName("org.jetbrains.kotlin.jps.build.KotlinBuilder") - return - } - catch (ClassNotFoundException ignored) { + if (getClass().getResource("/org/jetbrains/kotlin/jps/build/KotlinBuilder.class") != null) { + return true } - def kotlinPluginLibPath = "$home/build/dependencies/build/Kotlin/lib" + def kotlinPluginLibPath = "$home/build/dependencies/build/kotlin/Kotlin/lib" if (!new File(kotlinPluginLibPath).exists()) { - kotlinPluginLibPath = "$home/community/build/dependencies/build/Kotlin/lib" + kotlinPluginLibPath = "$home/community/build/dependencies/build/kotlin/Kotlin/lib" } if (!new File(kotlinPluginLibPath, "kotlin-runtime.jar").exists()) { projectBuilder.error("Could not find Kotlin JARs at $kotlinPluginLibPath: run `./gradlew setupKotlin` in dependencies module " + diff --git a/build/update.xml b/build/update.xml index 3decc239a398..123e91cd547f 100644 --- a/build/update.xml +++ b/build/update.xml @@ -53,19 +53,13 @@ - - - - - - diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java index edc9bac68de5..390682c04fe7 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -485,8 +485,12 @@ public class CompilerManagerImpl extends CompilerManager { public byte[] getContent() { return myBytes; } - } + @Override + public String toString() { + return getClassName(); + } + } private class ListenerNotificator implements CompileStatusNotification { private final @Nullable CompileStatusNotification myDelegate; diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceReader.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceReader.java index 560e9be70391..61a983b5f089 100644 --- a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceReader.java +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceReader.java @@ -237,7 +237,7 @@ class CompilerReferenceReader { } myIndex.get(CompilerIndices.BACK_HIERARCHY).getData(curClass).forEach((id, children) -> { for (LightRef child : children) { - if (child instanceof LightRef.LightClassHierarchyElementDef) { + if (child instanceof LightRef.LightClassHierarchyElementDef && !(child instanceof LightRef.LightAnonymousClassDef)) { q.addLast((LightRef.LightClassHierarchyElementDef) child); } } diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java index e23f8d0274f1..d77fa4fee8f7 100644 --- a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java @@ -38,6 +38,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.impl.LibraryScopeCache; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.ModificationTracker; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileWithId; @@ -156,12 +157,9 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx imp }); }); } - } - } - @Override - public void projectClosed() { - closeReaderIfNeed(false); + Disposer.register(myProject, () -> closeReaderIfNeed(false)); + } } @Nullable @@ -494,6 +492,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx imp try { if (myProject.isOpen()) { myReader = CompilerReferenceReader.create(myProject); + LOG.info("backward reference index reader " + (myReader == null ? "doesn't exist" : "is opened")); } } finally { myOpenCloseLock.unlock(); @@ -665,10 +664,10 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx imp } Throwable unwrapped = e instanceof RuntimeException ? e.getCause() : e; + LOG.error("an exception during " + actionName + " calculation", e); if (unwrapped instanceof PersistentEnumeratorBase.CorruptedException || unwrapped instanceof StorageException) { closeReaderIfNeed(true); } - LOG.error("an exception during " + actionName + " calculation", e); return null; } diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/JavaModuleIndexBuildTask.kt b/java/compiler/impl/src/com/intellij/compiler/impl/JavaModuleIndexBuildTask.kt index a929a0e26fdd..e90cee6527c1 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/JavaModuleIndexBuildTask.kt +++ b/java/compiler/impl/src/com/intellij/compiler/impl/JavaModuleIndexBuildTask.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -24,6 +24,7 @@ import com.intellij.openapi.compiler.CompilerManager import com.intellij.openapi.compiler.CompilerMessageCategory import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.roots.ModuleRootManager import com.intellij.psi.PsiJavaModule import com.intellij.psi.search.FilenameIndex import org.jetbrains.jps.builders.impl.BuildDataPathsImpl @@ -35,37 +36,50 @@ class JavaModuleIndexBuildTask : CompileTask { val systemDir = BuildManager.getInstance().getProjectSystemDirectory(project) if (systemDir == null) { - context.addMessage(CompilerMessageCategory.ERROR, "Internal error: no system directory for project: ${project}", null, 0, 0) + context.error("Internal error: no system directory for project: ${project}") return false } - val map = runReadAction { - val compilerManager = CompilerManager.getInstance(project) - ModuleManager.getInstance(project).modules.asSequence() - .map { - val files = FilenameIndex.getVirtualFilesByName(project, PsiJavaModule.MODULE_INFO_FILE, it.getModuleScope(false)) - it.name to files.filter { !compilerManager.isExcludedFromCompilation(it) } + val badModules = mutableListOf() + val paths = mutableMapOf() + + val compilerManager = CompilerManager.getInstance(project) + runReadAction { + ModuleManager.getInstance(project).modules.forEach { module -> + val index = ModuleRootManager.getInstance(module).fileIndex + val sourceFiles = mutableListOf() + val testFiles = mutableListOf() + FilenameIndex.getVirtualFilesByName(project, PsiJavaModule.MODULE_INFO_FILE, module.moduleScope).forEach { file -> + if (!compilerManager.isExcludedFromCompilation(file)) { + (if (index.isInTestSourceContent(file)) testFiles else sourceFiles) += file.path + } } - .toMap() + if (sourceFiles.size + testFiles.size > 1) { + badModules += module.name + } + else { + paths += module.name + JavaModuleIndexImpl.SOURCE_SUFFIX to sourceFiles.firstOrNull() + paths += module.name + JavaModuleIndexImpl.TEST_SUFFIX to testFiles.firstOrNull() + } + } } - val errors = map.filter { it.value.size > 1 }.map { IdeBundle.message("compiler.multiple.module.descriptors", it.key) } - if (errors.isNotEmpty()) { - errors.forEach { context.addMessage(CompilerMessageCategory.ERROR, it, null, 0, 0) } + if (badModules.isNotEmpty()) { + badModules.forEach { context.error(IdeBundle.message("compiler.multiple.module.descriptors", it)) } return false } - val paths = map.map { it.key to it.value.firstOrNull()?.path }.toMap() - try { JavaModuleIndexImpl.store(BuildDataPathsImpl(systemDir).dataStorageRoot, paths) } catch(e: Exception) { Logger.getInstance(JavaModuleIndexBuildTask::class.java).error(e) - context.addMessage(CompilerMessageCategory.ERROR, "Internal error: can't save module index: ${e.message}", null, 0, 0) + context.error("Internal error: can't save module index: ${e.message}") return false } return true } + + private fun CompileContext.error(message: String) = addMessage(CompilerMessageCategory.ERROR, message, null, 0, 0) } \ No newline at end of file diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index b1b0c24ac8c5..b40ec67fb65e 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -160,8 +160,9 @@ public class BuildManager implements Disposable { private final BuildProcessClasspathManager myClasspathManager = new BuildProcessClasspathManager(); private final ExecutorService myRequestsProcessor = SequentialTaskExecutor.createSequentialApplicationPoolExecutor("BuildManager requestProcessor pool"); private final Map myProjectDataMap = Collections.synchronizedMap(new HashMap()); + private volatile int myFileChangeCounter = 0; - private final BuildManagerPeriodicTask myAutoMakeTask = new BuildManagerPeriodicTask(this) { + private final BuildManagerPeriodicTask myAutoMakeTask = new BuildManagerPeriodicTask() { @Override protected int getDelay() { return Registry.intValue("compiler.automake.trigger.delay"); @@ -173,7 +174,7 @@ public class BuildManager implements Disposable { } }; - private final BuildManagerPeriodicTask myDocumentSaveTask = new BuildManagerPeriodicTask(this) { + private final BuildManagerPeriodicTask myDocumentSaveTask = new BuildManagerPeriodicTask() { @Override protected int getDelay() { return Registry.intValue("compiler.document.save.trigger.delay"); @@ -303,8 +304,14 @@ public class BuildManager implements Disposable { conn.subscribe(BatchFileChangeListener.TOPIC, new BatchFileChangeListener.Adapter() { @Override public void batchChangeStarted(Project project) { + myFileChangeCounter++; cancelAutoMakeTasks(project); } + + @Override + public void batchChangeCompleted(Project project) { + myFileChangeCounter--; + } }); EditorFactory.getInstance().getEventMulticaster().addDocumentListener(new DocumentAdapter() { @@ -1438,7 +1445,7 @@ public class BuildManager implements Disposable { } } - private abstract static class BuildManagerPeriodicTask implements Runnable { + private abstract class BuildManagerPeriodicTask implements Runnable { private final Alarm myAlarm; private final AtomicBoolean myInProgress = new AtomicBoolean(false); private final Runnable myTaskRunnable = () -> { @@ -1450,8 +1457,8 @@ public class BuildManager implements Disposable { } }; - protected BuildManagerPeriodicTask(@NotNull Disposable disposable) { - myAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, disposable); + protected BuildManagerPeriodicTask() { + myAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, BuildManager.this); } public final void schedule() { @@ -1470,7 +1477,7 @@ public class BuildManager implements Disposable { @Override public final void run() { - if (!HeavyProcessLatch.INSTANCE.isRunning() && !myInProgress.getAndSet(true)) { + if (!HeavyProcessLatch.INSTANCE.isRunning() && myFileChangeCounter <= 0 && !myInProgress.getAndSet(true)) { try { ApplicationManager.getApplication().executeOnPooledThread(myTaskRunnable); } diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java b/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java index cc93721f97fd..c6826bd53f3f 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.util.ArrayList; import java.util.List; /** @@ -93,13 +94,13 @@ public class BuildArtifactsBeforeRunTaskProvider extends BuildArtifactsBeforeRun public static void setBuildArtifactBeforeRun(@NotNull Project project, @NotNull RunConfiguration configuration, @NotNull Artifact artifact) { RunManagerEx runManager = RunManagerEx.getInstanceEx(project); - final List buildArtifactsTasks = runManager.getBeforeRunTasks(configuration, ID); - if (buildArtifactsTasks.isEmpty()) { //Add new task if absent + final List buildArtifactsTasks = new ArrayList<>(runManager.getBeforeRunTasks(configuration, ID)); + if (runManager.getBeforeRunTasks(configuration, ID).isEmpty()) { //Add new task if absent BuildArtifactsBeforeRunTask task = new BuildArtifactsBeforeRunTask(project); buildArtifactsTasks.add(task); - List tasks = runManager.getBeforeRunTasks(configuration); + List tasks = new ArrayList<>(runManager.getBeforeRunTasks(configuration)); tasks.add(task); - runManager.setBeforeRunTasks(configuration, tasks, false); + runManager.setBeforeRunTasks(configuration, tasks); } for (BuildArtifactsBeforeRunTask task : buildArtifactsTasks) { diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/EditSourceAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/EditSourceAction.java index dec60411ee1a..5c644854b043 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/EditSourceAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/EditSourceAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -30,9 +30,8 @@ import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; public class EditSourceAction extends DebuggerAction{ public void actionPerformed(AnActionEvent e) { @@ -84,11 +83,7 @@ public class EditSourceAction extends DebuggerAction{ } final NodeDescriptorImpl nodeDescriptor1 = nodeDescriptor; - return ApplicationManager.getApplication().runReadAction(new Computable() { - public SourcePosition compute() { - return SourcePositionProvider.getSourcePosition(nodeDescriptor1, project, context); - } - }); + return ReadAction.compute(() -> SourcePositionProvider.getSourcePosition(nodeDescriptor1, project, context)); } public void update(AnActionEvent e) { diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java index 85f164ec4e0e..84ab2aba6b65 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -27,9 +27,8 @@ import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl; import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl; import com.intellij.debugger.ui.tree.ValueDescriptor; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiClass; import com.intellij.util.containers.ContainerUtil; import com.sun.jdi.*; @@ -108,21 +107,18 @@ public class JumpToObjectAction extends DebuggerAction{ if (location != null) { SourcePosition position = debugProcess.getPositionManager().getSourcePosition(location); - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public SourcePosition compute() { - // adjust position for non-anonymous classes - if (clsType.name().indexOf('$') < 0) { - PsiClass classAt = JVMNameUtil.getClassAt(position); - if (classAt != null) { - SourcePosition classPosition = SourcePosition.createFromElement(classAt); - if (classPosition != null) { - return classPosition; - } + return ReadAction.compute(() -> { + // adjust position for non-anonymous classes + if (clsType.name().indexOf('$') < 0) { + PsiClass classAt = JVMNameUtil.getClassAt(position); + if (classAt != null) { + SourcePosition classPosition = SourcePosition.createFromElement(classAt); + if (classPosition != null) { + return classPosition; } } - return position; } + return position; }); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java index 9f276a22876f..510ad819f851 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java @@ -135,6 +135,9 @@ public class DebugProcessEvents extends DebugProcessImpl { @Override public void run() { + String oldThreadName = Thread.currentThread().getName(); + Thread.currentThread().setName("DebugProcessEvents"); + try { EventQueue eventQueue = myVmProxy.eventQueue(); while (!isStopped()) { @@ -271,6 +274,7 @@ public class DebugProcessEvents extends DebugProcessImpl { } finally { Thread.interrupted(); // reset interrupted status + Thread.currentThread().setName(oldThreadName); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java b/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java index 9a8f2e9651d5..84561dc600e6 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -21,11 +21,10 @@ import com.intellij.debugger.SourcePosition; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; import com.intellij.ide.util.JavaAnonymousClassesHelper; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; @@ -222,11 +221,7 @@ public class JVMNameUtil { List allClasses = process.getPositionManager().getAllClasses(mySourcePosition); // If there are more than one available, try to match by name if (allClasses.size() > 1) { - String name = ApplicationManager.getApplication().runReadAction(new Computable() { - public String compute() { - return getClassVMName(getClassAt(mySourcePosition)); - } - }); + String name = ReadAction.compute(() -> getClassVMName(getClassAt(mySourcePosition))); for (ReferenceType aClass : allClasses) { if (Comparing.equal(aClass.name(), name)) { return name; @@ -241,11 +236,7 @@ public class JVMNameUtil { } public String getDisplayName(final DebugProcessImpl debugProcess) { - return ApplicationManager.getApplication().runReadAction(new Computable() { - public String compute() { - return getSourcePositionClassDisplayName(debugProcess, mySourcePosition); - } - }); + return ReadAction.compute(() -> getSourcePositionClassDisplayName(debugProcess, mySourcePosition)); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java index ee817cd7ef17..fe4d073e93fa 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java @@ -37,11 +37,14 @@ import com.intellij.debugger.ui.breakpoints.Breakpoint; import com.intellij.debugger.ui.impl.watch.*; import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.lang.java.JavaLanguage; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -302,12 +305,7 @@ public class JavaStackFrame extends XStackFrame implements JVMStackFrameInfoProv Pair, Set> usedVars = EMPTY_USED_VARS; if (sourcePosition != null) { - usedVars = ApplicationManager.getApplication().runReadAction(new Computable, Set>>() { - @Override - public Pair, Set> compute() { - return findReferencedVars(ContainerUtil.union(visibleVariables.keySet(), visibleLocals), sourcePosition); - } - }); + usedVars = ReadAction.compute(() -> findReferencedVars(ContainerUtil.union(visibleVariables.keySet(), visibleLocals), sourcePosition)); } // add locals if (myAutoWatchMode) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java index 99f91a1ddda6..b5470faefe28 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java @@ -33,14 +33,14 @@ import com.intellij.debugger.ui.tree.*; import com.intellij.debugger.ui.tree.render.*; import com.intellij.debugger.ui.tree.render.Renderer; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.CommonClassNames; import com.intellij.psi.PsiElement; import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.ThreeState; import com.intellij.xdebugger.XExpression; import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; @@ -347,10 +347,8 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV @Override public void contextAction(@NotNull SuspendContextImpl suspendContext) throws Exception { - final XValueChildrenList children = new XValueChildrenList(); - final NodeRenderer renderer = myValueDescriptor.getRenderer(myEvaluationContext.getDebugProcess()); - final Ref remainingNum = new Ref<>(0); - renderer.buildChildren(myValueDescriptor.getValue(), new ChildrenBuilder() { + myValueDescriptor.getRenderer(myEvaluationContext.getDebugProcess()) + .buildChildren(myValueDescriptor.getValue(), new ChildrenBuilder() { @Override public NodeDescriptorFactory getDescriptorManager() { return myNodeManager; @@ -368,7 +366,7 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV @Override public void setRemaining(int remaining) { - remainingNum.set(remaining); + node.tooManyChildren(remaining); } @Override @@ -379,23 +377,38 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV } @Override - public void setChildren(List nodes) { - for (DebuggerTreeNode node : nodes) { - final NodeDescriptor descriptor = node.getDescriptor(); - if (descriptor instanceof ValueDescriptorImpl) { - // Value is calculated already in NodeManagerImpl - children.add(create(JavaValue.this, (ValueDescriptorImpl)descriptor, myEvaluationContext, myNodeManager, false)); - } - else if (descriptor instanceof MessageDescriptor) { - children.add(new JavaStackFrame.DummyMessageValueNode(descriptor.getLabel(), null)); - } + public void addChildren(List nodes, boolean last) { + if (nodes.isEmpty()) { + node.addChildren(XValueChildrenList.EMPTY, last); + } + else { + nodes.stream().map(DebuggerTreeNode::getDescriptor).forEach(descriptor -> { + if (descriptor instanceof ValueDescriptorImpl) { + // Value is calculated already in NodeManagerImpl + node.addChildren(XValueChildrenList.singleton( + create(JavaValue.this, (ValueDescriptorImpl)descriptor, myEvaluationContext, myNodeManager, false)), last); + } + else if (descriptor instanceof MessageDescriptor) { + node.addChildren(XValueChildrenList.singleton( + new JavaStackFrame.DummyMessageValueNode(descriptor.getLabel(), DebuggerTreeRenderer.getDescriptorIcon(descriptor))), last); + } + }); } } + + @Override + public void setChildren(List nodes) { + addChildren(nodes, true); + } + + @Override + public void setMessage(@NotNull String message, + @Nullable Icon icon, + @NotNull SimpleTextAttributes attributes, + @Nullable XDebuggerTreeNodeHyperlink link) { + node.setMessage(message, icon, attributes, link); + } }, myEvaluationContext); - node.addChildren(children, true); - if (remainingNum.get() > 0) { - node.tooManyChildren(remainingNum.get()); - } } }); } @@ -521,29 +534,26 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV @Override public void contextAction(@NotNull SuspendContextImpl suspendContext) throws Exception { - evaluationExpression = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public XExpression compute() { - try { - PsiElement psiExpression = getDescriptor().getTreeEvaluation(JavaValue.this, getDebuggerContext()); - if (psiExpression != null) { - XExpression res = TextWithImportsImpl.toXExpression(new TextWithImportsImpl(psiExpression)); - // add runtime imports if any - Set imports = psiExpression.getUserData(DebuggerTreeNodeExpression.ADDITIONAL_IMPORTS_KEY); - if (imports != null && res != null) { - if (res.getCustomInfo() != null) { - imports.add(res.getCustomInfo()); - } - res = new XExpressionImpl(res.getExpression(), res.getLanguage(), StringUtil.join(imports, ","), res.getMode()); + evaluationExpression = ReadAction.compute(() -> { + try { + PsiElement psiExpression = getDescriptor().getTreeEvaluation(JavaValue.this, getDebuggerContext()); + if (psiExpression != null) { + XExpression res = TextWithImportsImpl.toXExpression(new TextWithImportsImpl(psiExpression)); + // add runtime imports if any + Set imports = psiExpression.getUserData(DebuggerTreeNodeExpression.ADDITIONAL_IMPORTS_KEY); + if (imports != null && res != null) { + if (res.getCustomInfo() != null) { + imports.add(res.getCustomInfo()); } - return res; + res = new XExpressionImpl(res.getExpression(), res.getLanguage(), StringUtil.join(imports, ","), res.getMode()); } + return res; } - catch (EvaluateException e) { - LOG.info(e); - } - return null; } + catch (EvaluateException e) { + LOG.info(e); + } + return null; }); res.setResult(evaluationExpression); } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index cc0248b49442..8475a92325af 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -30,7 +30,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; @@ -50,6 +49,7 @@ import com.sun.jdi.Location; import com.sun.jdi.Method; import com.sun.jdi.ReferenceType; import com.sun.jdi.request.ClassPrepareRequest; +import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -92,38 +92,35 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio @Override public List createPrepareRequests(@NotNull final ClassPrepareRequestor requestor, @NotNull final SourcePosition position) throws NoDataException { - return ApplicationManager.getApplication().runReadAction(new Computable>() { - @Override - public List compute() { - List res = new ArrayList<>(); - for (PsiClass psiClass : getLineClasses(position.getFile(), position.getLine())) { - ClassPrepareRequestor prepareRequestor = requestor; - String classPattern = JVMNameUtil.getNonAnonymousClassName(psiClass); - if (classPattern == null) { - final PsiClass parent = JVMNameUtil.getTopLevelParentClass(psiClass); - if (parent == null) { - continue; - } - final String parentQName = JVMNameUtil.getNonAnonymousClassName(parent); - if (parentQName == null) { - continue; - } - classPattern = parentQName + "*"; - prepareRequestor = new ClassPrepareRequestor() { - public void processClassPrepare(DebugProcess debuggerProcess, ReferenceType referenceType) { - if (((DebugProcessImpl)debuggerProcess).getPositionManager().getAllClasses(position).contains(referenceType)) { - requestor.processClassPrepare(debuggerProcess, referenceType); - } + return ReadAction.compute(() -> { + List res = new ArrayList<>(); + for (PsiClass psiClass : getLineClasses(position.getFile(), position.getLine())) { + ClassPrepareRequestor prepareRequestor = requestor; + String classPattern = JVMNameUtil.getNonAnonymousClassName(psiClass); + if (classPattern == null) { + final PsiClass parent = JVMNameUtil.getTopLevelParentClass(psiClass); + if (parent == null) { + continue; + } + final String parentQName = JVMNameUtil.getNonAnonymousClassName(parent); + if (parentQName == null) { + continue; + } + classPattern = parentQName + "*"; + prepareRequestor = new ClassPrepareRequestor() { + public void processClassPrepare(DebugProcess debuggerProcess, ReferenceType referenceType) { + if (((DebugProcessImpl)debuggerProcess).getPositionManager().getAllClasses(position).contains(referenceType)) { + requestor.processClassPrepare(debuggerProcess, referenceType); } - }; - } - ClassPrepareRequest request = myDebugProcess.getRequestsManager().createClassPrepareRequest(prepareRequestor, classPattern); - if (request != null) { - res.add(request); - } + } + }; + } + ClassPrepareRequest request = myDebugProcess.getRequestsManager().createClassPrepareRequest(prepareRequestor, classPattern); + if (request != null) { + res.add(request); } - return res; } + return res; }); } @@ -444,19 +441,12 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio @NotNull public List getAllClasses(@NotNull final SourcePosition position) throws NoDataException { - return ApplicationManager.getApplication().runReadAction(new Computable>() { - @Override - public List compute() { - List res = new ArrayList<>(); - for (PsiClass aClass : getLineClasses(position.getFile(), position.getLine())) { - res.addAll(getClassReferences(aClass, position)); - } - return res; - } - }); + return ReadAction.compute(() -> StreamEx.of(getLineClasses(position.getFile(), position.getLine())) + .flatMap(aClass -> getClassReferences(aClass, position)) + .toList()); } - private List getClassReferences(@NotNull final PsiClass psiClass, SourcePosition position) { + private StreamEx getClassReferences(@NotNull final PsiClass psiClass, SourcePosition position) { ApplicationManager.getApplication().assertReadAccessAllowed(); boolean isLocalOrAnonymous = false; int requiredDepth = 0; @@ -484,23 +474,18 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio } if (className == null) { - return Collections.emptyList(); + return StreamEx.empty(); } if (!isLocalOrAnonymous) { - return myDebugProcess.getVirtualMachineProxy().classesByName(className); + return StreamEx.of(myDebugProcess.getVirtualMachineProxy().classesByName(className)); } - + + final int depth = requiredDepth; // the name is a parent class for a local or anonymous class - final List outers = myDebugProcess.getVirtualMachineProxy().classesByName(className); - final List result = new ArrayList<>(outers.size()); - for (ReferenceType outer : outers) { - final ReferenceType nested = findNested(outer, 0, psiClass, requiredDepth, position); - if (nested != null) { - result.add(nested); - } - } - return result; + return StreamEx.of(myDebugProcess.getVirtualMachineProxy().classesByName(className)) + .map(outer -> findNested(outer, 0, psiClass, depth, position)) + .nonNull(); } private static Pair getTopOrStaticEnclosingClass(PsiClass aClass) { @@ -644,11 +629,8 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio @Override public void visitClass(PsiClass aClass) { if (myCompiledMethod == null) { - final List allClasses = getClassReferences(aClass, SourcePosition.createFromElement(aClass)); - for (ReferenceType referenceType : allClasses) { - if (referenceType.name().equals(myClassName)) { - myCompiledClass = aClass; - } + if (getClassReferences(aClass, SourcePosition.createFromElement(aClass)).anyMatch(referenceType -> referenceType.name().equals(myClassName))) { + myCompiledClass = aClass; } aClass.acceptChildren(this); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/RequestHint.java b/java/debugger/impl/src/com/intellij/debugger/engine/RequestHint.java index f5adb418da5a..b6ff4f23ff1c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/RequestHint.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/RequestHint.java @@ -28,9 +28,8 @@ import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.jdi.StackFrameProxyImpl; import com.intellij.debugger.jdi.ThreadReferenceProxyImpl; import com.intellij.debugger.settings.DebuggerSettings; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiElement; import com.intellij.util.Range; import com.sun.jdi.Location; @@ -202,13 +201,11 @@ public class RequestHint { if ((myDepth == StepRequest.STEP_OVER || myDepth == StepRequest.STEP_INTO) && myPosition != null) { SourcePosition locationPosition = ContextUtil.getSourcePosition(context); if (locationPosition != null) { - Integer resultDepth = ApplicationManager.getApplication().runReadAction(new Computable() { - public Integer compute() { - if (myPosition.getFile().equals(locationPosition.getFile()) && isTheSameFrame(context) && !mySteppedOut) { - return isOnTheSameLine(locationPosition) ? myDepth : STOP; - } - return null; + Integer resultDepth = ReadAction.compute(() -> { + if (myPosition.getFile().equals(locationPosition.getFile()) && isTheSameFrame(context) && !mySteppedOut) { + return isOnTheSameLine(locationPosition) ? myDepth : STOP; } + return null; }); if (resultDepth != null) { return resultDepth.intValue(); @@ -231,11 +228,9 @@ public class RequestHint { if (!myIgnoreFilters) { if(settings.SKIP_GETTERS) { - boolean isGetter = ApplicationManager.getApplication().runReadAction(new Computable(){ - public Boolean compute() { - PsiElement contextElement = ContextUtil.getContextElement(context); - return contextElement != null && DebuggerUtils.isInsideSimpleGetter(contextElement); - } + boolean isGetter = ReadAction.compute(() -> { + PsiElement contextElement = ContextUtil.getContextElement(context); + return contextElement != null && DebuggerUtils.isInsideSimpleGetter(contextElement); }).booleanValue(); if(isGetter) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnBoxingEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnBoxingEvaluator.java index cefa3cecfef7..2e830e3d6013 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnBoxingEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnBoxingEvaluator.java @@ -15,16 +15,14 @@ */ package com.intellij.debugger.engine.evaluation.expression; -import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Couple; import com.intellij.psi.CommonClassNames; +import com.intellij.psi.impl.PsiJavaParserFacadeImpl; import com.intellij.util.containers.HashMap; -import com.sun.jdi.ClassType; -import com.sun.jdi.Method; -import com.sun.jdi.ObjectReference; -import com.sun.jdi.Value; +import com.sun.jdi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,7 +33,9 @@ import java.util.Map; * @author Eugene Zhuravlev * Date: Feb 8, 2010 */ -public class UnBoxingEvaluator implements Evaluator{ +public class UnBoxingEvaluator implements Evaluator { + private static final Logger LOG = Logger.getInstance(UnBoxingEvaluator.class); + private final Evaluator myOperand; private static final Map> TYPES_TO_CONVERSION_METHOD_MAP = new HashMap<>(); static { @@ -77,14 +77,32 @@ public class UnBoxingEvaluator implements Evaluator{ private static Value convertToPrimitive(EvaluationContextImpl context, ObjectReference value, final String conversionMethodName, String conversionMethodSignature) throws EvaluateException { - final DebugProcessImpl process = context.getDebugProcess(); - final ClassType wrapperClass = (ClassType)value.referenceType(); - Method method = wrapperClass.concreteMethodByName(conversionMethodName, conversionMethodSignature); + // for speedup first try value field + Value primitiveValue = getInnerPrimitiveValue(value); + if (primitiveValue != null) { + return primitiveValue; + } + + Method method = ((ClassType)value.referenceType()).concreteMethodByName(conversionMethodName, conversionMethodSignature); if (method == null) { throw new EvaluateException("Cannot convert to primitive value of type " + value.type() + ": Unable to find method " + conversionMethodName + conversionMethodSignature); } - return process.invokeMethod(context, value, method, Collections.emptyList()); + return context.getDebugProcess().invokeMethod(context, value, method, Collections.emptyList()); + } + + @Nullable + public static PrimitiveValue getInnerPrimitiveValue(ObjectReference value) { + ReferenceType type = value.referenceType(); + Field valueField = type.fieldByName("value"); + if (valueField != null) { + Value primitiveValue = value.getValue(valueField); + if (primitiveValue instanceof PrimitiveValue) { + LOG.assertTrue(type.name().equals(PsiJavaParserFacadeImpl.getPrimitiveType(primitiveValue.type().name()).getBoxedTypeName())); + return (PrimitiveValue)primitiveValue; + } + } + return null; } } \ No newline at end of file diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java index 32c2395e5d5d..c5513797d14d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java @@ -26,9 +26,8 @@ import com.intellij.debugger.requests.Requestor; import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.debugger.ui.breakpoints.FilteredRequestor; import com.intellij.diagnostic.ThreadDumper; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiClass; @@ -156,14 +155,12 @@ public class RequestManagerImpl extends DebugProcessAdapterImpl implements Reque if (!filter.isEnabled()) { continue; } - final JVMName jvmClassName = ApplicationManager.getApplication().runReadAction(new Computable() { - public JVMName compute() { - PsiClass psiClass = DebuggerUtils.findClass(filter.getPattern(), myDebugProcess.getProject(), myDebugProcess.getSearchScope()); - if (psiClass == null) { - return null; - } - return JVMNameUtil.getJVMQualifiedName(psiClass); + final JVMName jvmClassName = ReadAction.compute(() -> { + PsiClass psiClass = DebuggerUtils.findClass(filter.getPattern(), myDebugProcess.getProject(), myDebugProcess.getSearchScope()); + if (psiClass == null) { + return null; } + return JVMNameUtil.getJVMQualifiedName(psiClass); }); String pattern = filter.getPattern(); try { diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/InvokeThread.java b/java/debugger/impl/src/com/intellij/debugger/impl/InvokeThread.java index 825e943d402a..238d530388cc 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/InvokeThread.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/InvokeThread.java @@ -133,6 +133,9 @@ public abstract class InvokeThread { } private void run(final @NotNull WorkerThreadRequest threadRequest) { + String oldThreadName = Thread.currentThread().getName(); + Thread.currentThread().setName("DebuggerManagerThread"); + try { DumbService.getInstance(myProject).setAlternativeResolveEnabled(true); while(true) { @@ -183,6 +186,7 @@ public abstract class InvokeThread { LOG.debug("Request " + toString() + " exited"); DumbService.getInstance(myProject).setAlternativeResolveEnabled(false); + Thread.currentThread().setName(oldThreadName); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/PositionUtil.java b/java/debugger/impl/src/com/intellij/debugger/impl/PositionUtil.java index 47558e8c4da8..012e505791a7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/PositionUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/PositionUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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,10 +18,9 @@ package com.intellij.debugger.impl; import com.intellij.debugger.SourcePosition; import com.intellij.debugger.engine.ContextUtil; import com.intellij.debugger.engine.StackFrameContext; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -50,20 +49,18 @@ public class PositionUtil extends ContextUtil { @Nullable public static T getPsiElementAt(final Project project, final Class expectedPsiElementClass, final SourcePosition sourcePosition) { - return ApplicationManager.getApplication().runReadAction(new Computable() { - public T compute() { - final PsiFile psiFile = sourcePosition.getFile(); - final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); - if(document == null) { - return null; - } - final int spOffset = sourcePosition.getOffset(); - if (spOffset < 0) { - return null; - } - final int offset = CharArrayUtil.shiftForward(document.getCharsSequence(), spOffset, " \t"); - return PsiTreeUtil.getParentOfType(psiFile.findElementAt(offset), expectedPsiElementClass, false); + return ReadAction.compute(() -> { + final PsiFile psiFile = sourcePosition.getFile(); + final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); + if(document == null) { + return null; } + final int spOffset = sourcePosition.getOffset(); + if (spOffset < 0) { + return null; + } + final int offset = CharArrayUtil.shiftForward(document.getCharsSequence(), spOffset, " \t"); + return PsiTreeUtil.getParentOfType(psiFile.findElementAt(offset), expectedPsiElementClass, false); }); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariablesUtil.java b/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariablesUtil.java index a736e3c81e02..e2aa62a5fbc0 100644 --- a/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariablesUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariablesUtil.java @@ -22,9 +22,8 @@ import com.intellij.debugger.engine.StackFrameContext; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.impl.SimpleStackFrameContext; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ReflectionUtil; @@ -331,31 +330,28 @@ public class LocalVariablesUtil { private static MultiMap calcNames(@NotNull final StackFrameContext context, final int firstLocalsSlot) { SourcePosition position = ContextUtil.getSourcePosition(context); if (position != null) { - return ApplicationManager.getApplication().runReadAction(new Computable>() { - @Override - public MultiMap compute() { - PsiElement element = position.getElementAt(); - PsiElement method = DebuggerUtilsEx.getContainingMethod(element); - if (method != null) { - MultiMap res = new MultiMap<>(); - int slot = Math.max(0, firstLocalsSlot - getParametersStackSize(method)); - for (PsiParameter parameter : DebuggerUtilsEx.getParameters(method)) { - res.putValue(slot, parameter.getName()); - slot += getTypeSlotSize(parameter.getType()); - } - PsiElement body = DebuggerUtilsEx.getBody(method); - if (body != null) { - try { - body.accept(new LocalVariableNameFinder(firstLocalsSlot, res, element)); - } - catch (Exception e) { - LOG.info(e); - } - } - return res; + return ReadAction.compute(() -> { + PsiElement element = position.getElementAt(); + PsiElement method = DebuggerUtilsEx.getContainingMethod(element); + if (method != null) { + MultiMap res = new MultiMap<>(); + int slot = Math.max(0, firstLocalsSlot - getParametersStackSize(method)); + for (PsiParameter parameter : DebuggerUtilsEx.getParameters(method)) { + res.putValue(slot, parameter.getName()); + slot += getTypeSlotSize(parameter.getType()); } - return MultiMap.empty(); + PsiElement body = DebuggerUtilsEx.getBody(method); + if (body != null) { + try { + body.accept(new LocalVariableNameFinder(firstLocalsSlot, res, element)); + } + catch (Exception e) { + LOG.info(e); + } + } + return res; } + return MultiMap.empty(); }); } return MultiMap.empty(); diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/VirtualMachineProxyImpl.java b/java/debugger/impl/src/com/intellij/debugger/jdi/VirtualMachineProxyImpl.java index 55ebaef45f6a..3b351cf5b488 100644 --- a/java/debugger/impl/src/com/intellij/debugger/jdi/VirtualMachineProxyImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/jdi/VirtualMachineProxyImpl.java @@ -128,7 +128,7 @@ public class VirtualMachineProxyImpl implements JdiTimer, VirtualMachineProxy { } } - public List classesByName(String s) { + public List classesByName(@NotNull String s) { String signature = JNITypeParserReflect.typeNameToSignature(s); if (signature != null) { if (myAllClassesByName == null) { diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/filtering/ConditionChecker.java b/java/debugger/impl/src/com/intellij/debugger/memory/filtering/ConditionChecker.java index 9dcbc4fdba22..50c6eb94b5aa 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/filtering/ConditionChecker.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/filtering/ConditionChecker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -21,13 +21,9 @@ import org.jetbrains.annotations.NotNull; /** * @author Vitaliy.Bibaev */ +@FunctionalInterface public interface ConditionChecker { CheckingResult check(@NotNull ObjectReference ref); - ConditionChecker ALL_MATCHED_CHECKER = new ConditionChecker() { - @Override - public CheckingResult check(@NotNull ObjectReference ref) { - return CheckingResultImpl.SUCCESS; - } - }; + ConditionChecker ALL_MATCHED_CHECKER = ref -> CheckingResultImpl.SUCCESS; } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/filtering/ConditionCheckerImpl.java b/java/debugger/impl/src/com/intellij/debugger/memory/filtering/ConditionCheckerImpl.java index 45752525aa29..30b89c86a3cf 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/filtering/ConditionCheckerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/filtering/ConditionCheckerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,12 +22,11 @@ import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.engine.evaluation.TextWithImportsImpl; import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator; import com.intellij.debugger.engine.events.DebuggerContextCommandImpl; +import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.ui.tree.render.CachedEvaluator; import com.intellij.openapi.project.Project; import com.intellij.xdebugger.XExpression; -import com.sun.jdi.BooleanValue; import com.sun.jdi.ObjectReference; -import com.sun.jdi.Value; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -70,17 +69,11 @@ public class ConditionCheckerImpl implements ConditionChecker { @Override public void threadAction(@NotNull SuspendContextImpl suspendContext) { - ExpressionEvaluator evaluator; try { - evaluator = myEvaluator.getEvaluator(); - Value result = - evaluator.evaluate(new EvaluationContextImpl(suspendContext, suspendContext.getFrameProxy(), myReference)); - if (result instanceof BooleanValue && ((BooleanValue)result).value()) { - myResultReference.set(CheckingResultImpl.SUCCESS); - } - else { - myResultReference.set(CheckingResultImpl.FAIL); - } + EvaluationContextImpl evaluationContext = new EvaluationContextImpl(suspendContext, suspendContext.getFrameProxy(), myReference); + myResultReference.set(DebuggerUtilsEx.evaluateBoolean(myEvaluator.getEvaluator(), evaluationContext) + ? CheckingResultImpl.SUCCESS + : CheckingResultImpl.FAIL); } catch (EvaluateException e) { myResultReference.set(CheckingResultImpl.error(e.getMessage())); diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesFilteredView.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesFilteredView.java index b9dfc3a4dd35..8078423e8040 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesFilteredView.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesFilteredView.java @@ -253,12 +253,9 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable myDebugSessionListener = new MyDebuggerSessionListener(); debugSession.addSessionListener(myDebugSessionListener, this); - mySingleAlarm = new SingleAlarmWithMutableDelay(() -> { - final SuspendContextImpl suspendContext = debugProcess.getDebuggerContext().getSuspendContext(); - if (suspendContext != null) { - ApplicationManager.getApplication().invokeLater(() -> myTable.setBusy(true)); - managerThread.schedule(new MyUpdateClassesCommand(suspendContext)); - } + mySingleAlarm = new SingleAlarmWithMutableDelay(suspendContext -> { + ApplicationManager.getApplication().invokeLater(() -> myTable.setBusy(true)); + suspendContext.getDebugProcess().getManagerThread().schedule(new MyUpdateClassesCommand(suspendContext)); }, this); mySingleAlarm.setDelay((int)TimeUnit.MILLISECONDS.toMillis(500)); @@ -336,8 +333,12 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable if (debugSession != null) { final DebugProcess debugProcess = DebuggerManager.getInstance(myProject) .getDebugProcess(debugSession.getDebugProcess().getProcessHandler()); - if (debugProcess != null && debugProcess.isAttached()) { - mySingleAlarm.cancelAndRequest(); + if (debugProcess != null && debugProcess.isAttached() && debugProcess instanceof DebugProcessImpl) { + final DebugProcessImpl process = (DebugProcessImpl)debugProcess; + final SuspendContextImpl context = process.getDebuggerContext().getSuspendContext(); + if (context != null) { + mySingleAlarm.cancelAndRequest(context); + } } } }, x -> myProject.isDisposed()); diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/utils/InstancesProvider.java b/java/debugger/impl/src/com/intellij/debugger/memory/utils/InstancesProvider.java index 159c5884e5ff..43ea9f964b3f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/utils/InstancesProvider.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/utils/InstancesProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,6 +20,7 @@ import org.jetbrains.annotations.NotNull; import java.util.List; +@FunctionalInterface public interface InstancesProvider { @NotNull List getInstances(int limit); diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/utils/SingleAlarmWithMutableDelay.java b/java/debugger/impl/src/com/intellij/debugger/memory/utils/SingleAlarmWithMutableDelay.java index 879b46d8ec90..036ba7faf904 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/utils/SingleAlarmWithMutableDelay.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/utils/SingleAlarmWithMutableDelay.java @@ -15,16 +15,19 @@ */ package com.intellij.debugger.memory.utils; +import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.openapi.Disposable; import com.intellij.util.Alarm; import org.jetbrains.annotations.NotNull; -public class SingleAlarmWithMutableDelay extends Alarm { - private final Runnable myTask; +public class SingleAlarmWithMutableDelay { + private final Alarm myAlarm; + private final Task myTask; + private volatile int myDelayMillis; - public SingleAlarmWithMutableDelay(@NotNull Runnable task, @NotNull Disposable parentDisposable) { - super(ThreadToUse.POOLED_THREAD, parentDisposable); + public SingleAlarmWithMutableDelay(@NotNull Task task, @NotNull Disposable parentDisposable) { + myAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, parentDisposable); myTask = task; } @@ -32,10 +35,23 @@ public class SingleAlarmWithMutableDelay extends Alarm { myDelayMillis = millis; } - public void cancelAndRequest() { - if (!isDisposed()) { + public void cancelAndRequest(@NotNull SuspendContextImpl suspendContext) { + if (!myAlarm.isDisposed()) { cancelAllRequests(); - addRequest(myTask, myDelayMillis); + addRequest(() -> myTask.run(suspendContext)); } } + + public void cancelAllRequests() { + myAlarm.cancelAllRequests(); + } + + private void addRequest(@NotNull Runnable runnable) { + myAlarm.addRequest(runnable, myDelayMillis); + } + + @FunctionalInterface + public interface Task { + void run(@NotNull SuspendContextImpl suspendContext); + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/ValueHint.java b/java/debugger/impl/src/com/intellij/debugger/ui/ValueHint.java index 5e2bdc5aa862..f73e40621738 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/ValueHint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/ValueHint.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -40,7 +40,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.CustomShortcutSet; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; @@ -123,12 +123,7 @@ public class ValueHint extends AbstractValueHint { try { final EvaluationContextImpl evaluationContext = debuggerContext.createEvaluationContext(); - final String expressionText = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return myCurrentExpression.getText(); - } - }); + final String expressionText = ReadAction.compute(() -> myCurrentExpression.getText()); final TextWithImports text = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, expressionText); final Value value = myValueToShow != null? myValueToShow : evaluator.evaluate(evaluationContext); @@ -194,13 +189,7 @@ public class ValueHint extends AbstractValueHint { @Override public void threadAction() { descriptor.setRenderer(debugProcess.getAutoRenderer(descriptor)); - final String expressionText = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return myCurrentExpression.getText(); - } - }); - + final String expressionText = ReadAction.compute(() -> myCurrentExpression.getText()); createAndShowTree(expressionText, descriptor); } }); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java index 11d828cffe49..e260a8b6d000 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java @@ -32,6 +32,7 @@ import com.intellij.debugger.impl.DebuggerSession; import com.intellij.debugger.ui.JavaDebuggerSupport; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -42,7 +43,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; @@ -247,7 +247,7 @@ public class BreakpointManager { public ExceptionBreakpoint addExceptionBreakpoint(@NotNull final String exceptionClassName, final String packageName) { ApplicationManager.getApplication().assertIsDispatchThread(); final JavaExceptionBreakpointType type = XDebuggerUtil.getInstance().findBreakpointType(JavaExceptionBreakpointType.class); - return ApplicationManager.getApplication().runWriteAction((Computable)() -> { + return WriteAction.compute(() -> { XBreakpoint xBreakpoint = XDebuggerManager.getInstance(myProject).getBreakpointManager() .addBreakpoint(type, new JavaExceptionBreakpointProperties(exceptionClassName, packageName)); Breakpoint javaBreakpoint = getJavaBreakpoint(xBreakpoint); @@ -279,7 +279,7 @@ public class BreakpointManager { private > XLineBreakpoint addXLineBreakpoint(Class> typeCls, Document document, final int lineIndex) { final XBreakpointType type = XDebuggerUtil.getInstance().findBreakpointType(typeCls); final VirtualFile file = FileDocumentManager.getInstance().getFile(document); - return ApplicationManager.getApplication().runWriteAction((Computable)() -> XDebuggerManager.getInstance(myProject).getBreakpointManager() + return WriteAction.compute(() -> XDebuggerManager.getInstance(myProject).getBreakpointManager() .addLineBreakpoint((XLineBreakpointType)type, file.getUrl(), lineIndex, ((XLineBreakpointType)type).createBreakpointProperties(file, lineIndex))); } @@ -443,7 +443,7 @@ public class BreakpointManager { private > XBreakpoint createXBreakpoint(Class> typeCls) { final XBreakpointType type = XDebuggerUtil.getInstance().findBreakpointType(typeCls); - return ApplicationManager.getApplication().runWriteAction((Computable)() -> XDebuggerManager.getInstance(myProject).getBreakpointManager().addBreakpoint((XBreakpointType)type, type.createProperties())); + return WriteAction.compute(() -> XDebuggerManager.getInstance(myProject).getBreakpointManager().addBreakpoint((XBreakpointType)type, type.createProperties())); } private > XLineBreakpoint createXLineBreakpoint(Class> typeCls, @@ -479,7 +479,7 @@ public class BreakpointManager { if (breakpoint == null) { return; } - ApplicationManager.getApplication().runWriteAction(() -> getXBreakpointManager().removeBreakpoint(breakpoint.myXBreakpoint)); + WriteAction.run(() -> getXBreakpointManager().removeBreakpoint(breakpoint.myXBreakpoint)); } public void writeExternal(@NotNull final Element parentNode) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java index 8ccee6bf428a..075239a3991c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java @@ -25,11 +25,11 @@ import com.intellij.debugger.engine.requests.RequestManagerImpl; import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; @@ -184,12 +184,7 @@ public abstract class BreakpointWithHighlighter

() { - @Override - public Boolean compute() { - return sourcePosition != null && sourcePosition.getFile().isValid(); - } - }).booleanValue(); + return ReadAction.compute(() -> sourcePosition != null && sourcePosition.getFile().isValid()).booleanValue(); } @Nullable @@ -344,13 +339,7 @@ public abstract class BreakpointWithHighlighter

() { - @Nullable - @Override - public PsiClass compute() { - return JVMNameUtil.getClassAt(sourcePosition); - } - }); + return ReadAction.compute(() -> JVMNameUtil.getClassAt(sourcePosition)); } @Override @@ -403,13 +392,8 @@ public abstract class BreakpointWithHighlighter

() { - @Override - public String compute() { - return CommonXmlStrings.HTML_START + CommonXmlStrings.BODY_START - + getDescription() - + CommonXmlStrings.BODY_END + CommonXmlStrings.HTML_END; - } - }); + return ReadAction.compute(() -> CommonXmlStrings.HTML_START + CommonXmlStrings.BODY_START + + getDescription() + + CommonXmlStrings.BODY_END + CommonXmlStrings.HTML_END); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java index 956630d0c763..6db976eb4446 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -29,11 +29,9 @@ import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.engine.requests.RequestManagerImpl; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.icons.AllIcons; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizerUtil; import com.intellij.openapi.util.Key; @@ -122,12 +120,9 @@ public class ExceptionBreakpoint extends Breakpoint() { - public SourcePosition compute() { - PsiClass psiClass = DebuggerUtils.findClass(getQualifiedName(), myProject, debugProcess.getSearchScope()); - - return psiClass != null ? SourcePosition.createFromElement(psiClass) : null; - } + SourcePosition classPosition = ReadAction.compute(() -> { + PsiClass psiClass = DebuggerUtils.findClass(getQualifiedName(), myProject, debugProcess.getSearchScope()); + return psiClass != null ? SourcePosition.createFromElement(psiClass) : null; }); if(classPosition == null) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaExceptionBreakpointType.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaExceptionBreakpointType.java index b4883e10f48a..3af57ecf8035 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaExceptionBreakpointType.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaExceptionBreakpointType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -21,9 +21,8 @@ import com.intellij.debugger.engine.JVMNameUtil; import com.intellij.icons.AllIcons; import com.intellij.ide.util.TreeClassChooser; import com.intellij.ide.util.TreeClassChooserFactory; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; import com.intellij.psi.CommonClassNames; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; @@ -128,13 +127,8 @@ public class JavaExceptionBreakpointType extends JavaBreakpointTypeBase 0) { - return ApplicationManager.getApplication().runWriteAction(new Computable>() { - @Override - public XBreakpoint compute() { - return XDebuggerManager.getInstance(project).getBreakpointManager().addBreakpoint( - JavaExceptionBreakpointType.this, new JavaExceptionBreakpointProperties(qName, ((PsiClassOwner)selectedClass.getContainingFile()).getPackageName())); - } - }); + return WriteAction.compute(() -> XDebuggerManager.getInstance(project).getBreakpointManager() + .addBreakpoint(this, new JavaExceptionBreakpointProperties(qName, ((PsiClassOwner)selectedClass.getContainingFile()).getPackageName()))); } return null; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaFieldBreakpointType.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaFieldBreakpointType.java index d40bc8023c8c..410a8221b751 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaFieldBreakpointType.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaFieldBreakpointType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -19,7 +19,7 @@ import com.intellij.CommonBundle; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.HelpID; import com.intellij.icons.AllIcons; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; @@ -146,7 +146,7 @@ public class JavaFieldBreakpointType extends JavaLineBreakpointTypeBase { + WriteAction.run(() -> { XLineBreakpoint fieldBreakpoint = XDebuggerManager.getInstance(project).getBreakpointManager() .addLineBreakpoint(JavaFieldBreakpointType.this, psiFile.getVirtualFile().getUrl(), line, new JavaFieldBreakpointProperties(fieldName, className)); result.set(fieldBreakpoint); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaWildcardMethodBreakpointType.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaWildcardMethodBreakpointType.java index 990850708e55..ecab88d344bd 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaWildcardMethodBreakpointType.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaWildcardMethodBreakpointType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,9 +18,8 @@ package com.intellij.debugger.ui.breakpoints; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.HelpID; import com.intellij.icons.AllIcons; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.registry.Registry; import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.breakpoints.XBreakpoint; @@ -104,7 +103,7 @@ public class JavaWildcardMethodBreakpointType extends JavaBreakpointTypeBase>)() -> { + return WriteAction.compute(() -> { JavaMethodBreakpointProperties properties = new JavaMethodBreakpointProperties(dialog.getClassPattern(), dialog.getMethodName()); if (Registry.is("debugger.emulate.method.breakpoints")) { properties.EMULATED = true; // create all new emulated diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java index 052ac43562f8..e28d980600bf 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java @@ -31,7 +31,6 @@ import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.jdi.StackFrameProxyImpl; import com.intellij.icons.AllIcons; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -39,7 +38,6 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VirtualFile; @@ -269,46 +267,42 @@ public class LineBreakpoint

extends Breakpoi private Collection findClassCandidatesInSourceContent(final String className, final GlobalSearchScope scope, final ProjectFileIndex fileIndex) { final int dollarIndex = className.indexOf("$"); final String topLevelClassName = dollarIndex >= 0? className.substring(0, dollarIndex) : className; - return ApplicationManager.getApplication().runReadAction(new Computable>() { - @Override - @Nullable - public Collection compute() { - final PsiClass[] classes = JavaPsiFacade.getInstance(myProject).findClasses(topLevelClassName, scope); + return ReadAction.compute(() -> { + final PsiClass[] classes = JavaPsiFacade.getInstance(myProject).findClasses(topLevelClassName, scope); + if (LOG.isDebugEnabled()) { + LOG.debug("Found "+ classes.length + " classes " + topLevelClassName + " in scope "+scope); + } + if (classes.length == 0) { + return null; + } + final List list = new ArrayList<>(classes.length); + for (PsiClass aClass : classes) { + final PsiFile psiFile = aClass.getContainingFile(); + if (LOG.isDebugEnabled()) { - LOG.debug("Found "+ classes.length + " classes " + topLevelClassName + " in scope "+scope); + final StringBuilder msg = new StringBuilder(); + msg.append("Checking class ").append(aClass.getQualifiedName()); + msg.append("\n\t").append("PsiFile=").append(psiFile); + if (psiFile != null) { + final VirtualFile vFile = psiFile.getVirtualFile(); + msg.append("\n\t").append("VirtualFile=").append(vFile); + if (vFile != null) { + msg.append("\n\t").append("isInSourceContent=").append(fileIndex.isUnderSourceRootOfType(vFile, JavaModuleSourceRootTypes.SOURCES)); + } + } + LOG.debug(msg.toString()); } - if (classes.length == 0) { + + if (psiFile == null) { return null; } - final List list = new ArrayList<>(classes.length); - for (PsiClass aClass : classes) { - final PsiFile psiFile = aClass.getContainingFile(); - - if (LOG.isDebugEnabled()) { - final StringBuilder msg = new StringBuilder(); - msg.append("Checking class ").append(aClass.getQualifiedName()); - msg.append("\n\t").append("PsiFile=").append(psiFile); - if (psiFile != null) { - final VirtualFile vFile = psiFile.getVirtualFile(); - msg.append("\n\t").append("VirtualFile=").append(vFile); - if (vFile != null) { - msg.append("\n\t").append("isInSourceContent=").append(fileIndex.isUnderSourceRootOfType(vFile, JavaModuleSourceRootTypes.SOURCES)); - } - } - LOG.debug(msg.toString()); - } - - if (psiFile == null) { - return null; - } - final VirtualFile vFile = psiFile.getVirtualFile(); - if (vFile == null || !fileIndex.isUnderSourceRootOfType(vFile, JavaModuleSourceRootTypes.SOURCES)) { - return null; // this will switch off the check if at least one class is from libraries - } - list.add(vFile); + final VirtualFile vFile = psiFile.getVirtualFile(); + if (vFile == null || !fileIndex.isUnderSourceRootOfType(vFile, JavaModuleSourceRootTypes.SOURCES)) { + return null; // this will switch off the check if at least one class is from libraries } - return list; + list.add(vFile); } + return list; }); } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java index 4c9e8cb5a2d4..6ab93c6116af 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java @@ -36,6 +36,7 @@ import com.intellij.debugger.jdi.MethodBytecodeUtil; import com.intellij.debugger.requests.Requestor; import com.intellij.icons.AllIcons; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.progress.ProgressIndicator; @@ -43,7 +44,10 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.util.ProgressWindow; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.JDOMExternalizerUtil; +import com.intellij.openapi.util.Key; import com.intellij.psi.*; import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.containers.ContainerUtil; @@ -441,37 +445,34 @@ public class MethodBreakpoint extends BreakpointWithHighlighter() { // conflicts with readAction on initial breakpoints creation - final MethodDescriptor descriptor = ApplicationManager.getApplication().runReadAction(new Computable() { - @Nullable - public MethodDescriptor compute() { - //PsiMethod method = DebuggerUtilsEx.findPsiMethod(psiJavaFile, endOffset); - PsiMethod method = PositionUtil.getPsiElementAt(project, PsiMethod.class, sourcePosition); - if (method == null) { - return null; - } - final int methodOffset = method.getTextOffset(); - if (methodOffset < 0) { - return null; - } - if (document.getLineNumber(methodOffset) < sourcePosition.getLine()) { - return null; - } - - final PsiIdentifier identifier = method.getNameIdentifier(); - int methodNameOffset = identifier != null? identifier.getTextOffset() : methodOffset; - final MethodDescriptor descriptor = - new MethodDescriptor(); - descriptor.methodName = JVMNameUtil.getJVMMethodName(method); - try { - descriptor.methodSignature = JVMNameUtil.getJVMSignature(method); - descriptor.isStatic = method.hasModifierProperty(PsiModifier.STATIC); - } - catch (IndexNotReadyException ignored) { - return null; - } - descriptor.methodLine = document.getLineNumber(methodNameOffset); - return descriptor; + final MethodDescriptor descriptor = ReadAction.compute(() -> { + //PsiMethod method = DebuggerUtilsEx.findPsiMethod(psiJavaFile, endOffset); + PsiMethod method = PositionUtil.getPsiElementAt(project, PsiMethod.class, sourcePosition); + if (method == null) { + return null; } + final int methodOffset = method.getTextOffset(); + if (methodOffset < 0) { + return null; + } + if (document.getLineNumber(methodOffset) < sourcePosition.getLine()) { + return null; + } + + final PsiIdentifier identifier = method.getNameIdentifier(); + int methodNameOffset = identifier != null? identifier.getTextOffset() : methodOffset; + final MethodDescriptor res = + new MethodDescriptor(); + res.methodName = JVMNameUtil.getJVMMethodName(method); + try { + res.methodSignature = JVMNameUtil.getJVMSignature(method); + res.isStatic = method.hasModifierProperty(PsiModifier.STATIC); + } + catch (IndexNotReadyException ignored) { + return null; + } + res.methodLine = document.getLineNumber(methodNameOffset); + return res; }); if (descriptor == null || descriptor.methodName == null || descriptor.methodSignature == null) { return null; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java index fb8a715d3a88..944e32e0c436 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java @@ -19,6 +19,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.ui.impl.watch.*; +import com.intellij.debugger.ui.tree.NodeDescriptor; import com.intellij.debugger.ui.tree.ValueDescriptor; import com.intellij.debugger.ui.tree.render.EnumerationChildrenRenderer; import com.intellij.icons.AllIcons; @@ -62,7 +63,7 @@ public class DebuggerTreeRenderer extends ColoredTreeCellRenderer { } @Nullable - public static Icon getDescriptorIcon(NodeDescriptorImpl descriptor) { + public static Icon getDescriptorIcon(NodeDescriptor descriptor) { Icon nodeIcon = null; if (descriptor instanceof ThreadGroupDescriptorImpl) { nodeIcon = (((ThreadGroupDescriptorImpl)descriptor).isCurrent() ? AllIcons.Debugger.ThreadGroupCurrent : AllIcons.Debugger.ThreadGroup); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java index 599eabc1d9c6..da962f223050 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java @@ -22,7 +22,6 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.settings.ViewsGeneralSettings; import com.intellij.debugger.ui.impl.watch.ArrayElementDescriptorImpl; -import com.intellij.debugger.ui.impl.watch.MessageDescriptor; import com.intellij.debugger.ui.impl.watch.NodeManagerImpl; import com.intellij.debugger.ui.tree.DebuggerTreeNode; import com.intellij.debugger.ui.tree.NodeDescriptor; @@ -37,6 +36,7 @@ import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiElementFactory; import com.intellij.psi.PsiExpression; +import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.IncorrectOperationException; import com.sun.jdi.ArrayReference; import com.sun.jdi.ArrayType; @@ -45,8 +45,7 @@ import com.sun.jdi.Value; import org.jdom.Element; import org.jetbrains.annotations.NonNls; -import java.util.ArrayList; -import java.util.List; +import java.util.Collections; /** * User: lex @@ -58,11 +57,6 @@ public class ArrayRenderer extends NodeRendererImpl{ public static final @NonNls String UNIQUE_ID = "ArrayRenderer"; - public static final MessageDescriptor ALL_ELEMENTS_IN_RANGE_ARE_NULL = - new MessageDescriptor(DebuggerBundle.message("message.node.all.elements.null")); - public static final MessageDescriptor HIDDEN_NULL_ELEMENTS = - new MessageDescriptor(DebuggerBundle.message("message.node.elements.null.hidden")); - public int START_INDEX = 0; public int END_INDEX = 100; public int ENTRIES_LIMIT = 101; @@ -99,7 +93,6 @@ public class ArrayRenderer extends NodeRendererImpl{ public void buildChildren(Value value, ChildrenBuilder builder, EvaluationContext evaluationContext) { DebuggerManagerThreadImpl.assertIsManagerThread(); - List children = new ArrayList<>(); NodeManagerImpl nodeManager = (NodeManagerImpl)builder.getNodeManager(); NodeDescriptorFactory descriptorFactory = builder.getDescriptorManager(); @@ -133,7 +126,7 @@ public class ArrayRenderer extends NodeRendererImpl{ continue; } - children.add(arrayItemNode); + builder.addChildren(Collections.singletonList(arrayItemNode), false); added++; if (added > ENTRIES_LIMIT) { break; @@ -141,24 +134,26 @@ public class ArrayRenderer extends NodeRendererImpl{ } } + builder.addChildren(Collections.emptyList(), true); + if (added == 0) { if (START_INDEX == 0 && array.length() - 1 <= END_INDEX) { - children.add(nodeManager.createMessageNode(ALL_ELEMENTS_IN_RANGE_ARE_NULL)); + builder.setMessage(DebuggerBundle.message("message.node.all.elements.null"), null, SimpleTextAttributes.REGULAR_ATTRIBUTES, null); } else { - children.add(nodeManager.createMessageNode(DebuggerBundle.message("message.node.all.array.elements.null", START_INDEX, END_INDEX))); + builder.setMessage(DebuggerBundle.message("message.node.all.array.elements.null", START_INDEX, END_INDEX), null, + SimpleTextAttributes.REGULAR_ATTRIBUTES, null); } } else { if (hiddenNulls) { - children.add(0, nodeManager.createMessageNode(HIDDEN_NULL_ELEMENTS)); + builder.setMessage(DebuggerBundle.message("message.node.elements.null.hidden"), null, SimpleTextAttributes.REGULAR_ATTRIBUTES, null); } if (!myForced && END_INDEX < array.length() - 1) { builder.setRemaining(array.length() - 1 - END_INDEX); } } } - builder.setChildren(children); } private static boolean elementIsNull(ArrayReference arrayReference, int index) { @@ -200,6 +195,6 @@ public class ArrayRenderer extends NodeRendererImpl{ } public boolean isApplicable(Type type) { - return (type instanceof ArrayType); + return type instanceof ArrayType; } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ChildrenBuilder.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ChildrenBuilder.java index e98867a81496..416089ed0de7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ChildrenBuilder.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ChildrenBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -16,7 +16,12 @@ package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.ui.tree.*; +import com.intellij.ui.SimpleTextAttributes; +import com.intellij.xdebugger.frame.XDebuggerTreeNodeHyperlink; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.util.List; public interface ChildrenBuilder { @@ -28,6 +33,16 @@ public interface ChildrenBuilder { void setChildren(List children); + default void addChildren(List children, boolean last) { + setChildren(children); + } + + default void setMessage(@NotNull String message, + @Nullable Icon icon, + @NotNull SimpleTextAttributes attributes, + @Nullable XDebuggerTreeNodeHyperlink link) { + } + void setRemaining(int remaining); void initChildrenArrayRenderer(ArrayRenderer renderer); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/UnboxableTypeRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/UnboxableTypeRenderer.java new file mode 100644 index 000000000000..a76516600258 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/UnboxableTypeRenderer.java @@ -0,0 +1,99 @@ +/* + * Copyright 2000-2017 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.debugger.ui.tree.render; + +import com.intellij.debugger.engine.DebuggerUtils; +import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.debugger.engine.evaluation.EvaluationContext; +import com.intellij.debugger.engine.evaluation.expression.UnBoxingEvaluator; +import com.intellij.debugger.settings.NodeRendererSettings; +import com.intellij.debugger.ui.tree.ValueDescriptor; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.CommonClassNames; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.Type; + +/** + * @author egor + */ +public abstract class UnboxableTypeRenderer extends CompoundReferenceRenderer { + public UnboxableTypeRenderer(String className, NodeRendererSettings rendererSettings) { + super(rendererSettings, StringUtil.getShortName(className), new LabelRenderer() { + @Override + public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener labelListener) + throws EvaluateException { + return DebuggerUtils.getValueAsString(evaluationContext, UnBoxingEvaluator.getInnerPrimitiveValue((ObjectReference)descriptor.getValue())); + } + }, null); + LOG.assertTrue(UnBoxingEvaluator.isTypeUnboxable(className)); + setClassName(className); + setEnabled(true); + } + + @Override + public boolean isApplicable(Type type) { + return type instanceof ReferenceType && StringUtil.equals(type.name(), getClassName()); + } + + public static class BooleanRenderer extends UnboxableTypeRenderer { + public BooleanRenderer(NodeRendererSettings rendererSettings) { + super(CommonClassNames.JAVA_LANG_BOOLEAN, rendererSettings); + } + } + + public static class ByteRenderer extends UnboxableTypeRenderer { + public ByteRenderer(NodeRendererSettings rendererSettings) { + super(CommonClassNames.JAVA_LANG_BYTE, rendererSettings); + } + } + + public static class CharacterRenderer extends UnboxableTypeRenderer { + public CharacterRenderer(NodeRendererSettings rendererSettings) { + super(CommonClassNames.JAVA_LANG_CHARACTER, rendererSettings); + } + } + + public static class ShortRenderer extends UnboxableTypeRenderer { + public ShortRenderer(NodeRendererSettings rendererSettings) { + super(CommonClassNames.JAVA_LANG_SHORT, rendererSettings); + } + } + + public static class IntegerRenderer extends UnboxableTypeRenderer { + public IntegerRenderer(NodeRendererSettings rendererSettings) { + super(CommonClassNames.JAVA_LANG_INTEGER, rendererSettings); + } + } + + public static class LongRenderer extends UnboxableTypeRenderer { + public LongRenderer(NodeRendererSettings rendererSettings) { + super(CommonClassNames.JAVA_LANG_LONG, rendererSettings); + } + } + + public static class FloatRenderer extends UnboxableTypeRenderer { + public FloatRenderer(NodeRendererSettings rendererSettings) { + super(CommonClassNames.JAVA_LANG_FLOAT, rendererSettings); + } + } + + public static class DoubleRenderer extends UnboxableTypeRenderer { + public DoubleRenderer(NodeRendererSettings rendererSettings) { + super(CommonClassNames.JAVA_LANG_DOUBLE, rendererSettings); + } + } +} diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java b/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java index ef55ee92e099..a48a908d6c4c 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java @@ -72,20 +72,19 @@ public abstract class DebuggerUtils { return ((StringReference)value).value(); } if (isInteger(value)) { - long v = ((PrimitiveValue)value).longValue(); - return String.valueOf(v); + return String.valueOf(((PrimitiveValue)value).longValue()); } - if (isNumeric(value)) { - double v = ((PrimitiveValue)value).doubleValue(); - return String.valueOf(v); + if (value instanceof FloatValue) { + return String.valueOf(((FloatValue)value).floatValue()); + } + if (value instanceof DoubleValue) { + return String.valueOf(((DoubleValue)value).doubleValue()); } if (value instanceof BooleanValue) { - boolean v = ((PrimitiveValue)value).booleanValue(); - return String.valueOf(v); + return String.valueOf(((PrimitiveValue)value).booleanValue()); } if (value instanceof CharValue) { - char v = ((PrimitiveValue)value).charValue(); - return String.valueOf(v); + return String.valueOf(((PrimitiveValue)value).charValue()); } if (value instanceof ObjectReference) { if (value instanceof ArrayReference) { diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/VirtualMachineProxy.java b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/VirtualMachineProxy.java index ab116c9e2fc5..2c3f6bd3c8a1 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/VirtualMachineProxy.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/VirtualMachineProxy.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package com.intellij.debugger.engine.jdi; import com.intellij.debugger.engine.DebugProcess; import com.sun.jdi.ReferenceType; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -40,5 +41,5 @@ public interface VirtualMachineProxy { List nestedTypes(ReferenceType refType); - List classesByName(String s); + List classesByName(@NotNull String s); } diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java index a9039bc4a830..86b394f2c5d9 100644 --- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java @@ -246,12 +246,17 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration envs = getEnvs(); + //if (!envs.isEmpty()) { + EnvironmentVariablesComponent.writeExternal(element, envs); + //} } public static class JavaApplicationCommandLineState extends BaseJavaApplicationCommandLineState { @@ -297,15 +302,13 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration JavaModuleGraphUtil.findDescriptorByElement(module.findClass(params.getMainClass()))); + if (mainModule != null) { + params.setModuleName(mainModule.getName()); + PathsList classPath = params.getClassPath(), modulePath = params.getModulePath(); + modulePath.addAll(classPath.getPathList()); + classPath.clear(); } } } diff --git a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java index 2fa79311b8c6..91bcef935b00 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java +++ b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java @@ -219,7 +219,7 @@ public class JUnitUtil { return false; } - public static boolean isJUnit5TestClass(final PsiClass psiClass, boolean checkAbstract) { + public static boolean isJUnit5TestClass(@NotNull final PsiClass psiClass, boolean checkAbstract) { final PsiModifierList modifierList = psiClass.getModifierList(); if (modifierList == null) return false; diff --git a/java/execution/impl/src/com/intellij/execution/testframework/SearchForTestsTask.java b/java/execution/impl/src/com/intellij/execution/testframework/SearchForTestsTask.java index 74a9f465a87c..6df268e6c6d2 100644 --- a/java/execution/impl/src/com/intellij/execution/testframework/SearchForTestsTask.java +++ b/java/execution/impl/src/com/intellij/execution/testframework/SearchForTestsTask.java @@ -15,6 +15,7 @@ */ package com.intellij.execution.testframework; +import com.intellij.concurrency.SensitiveProgressWrapper; import com.intellij.execution.ExecutionBundle; import com.intellij.execution.ExecutionException; import com.intellij.execution.process.OSProcessHandler; @@ -27,6 +28,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; +import com.intellij.openapi.progress.util.ProgressIndicatorUtils; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; @@ -36,6 +38,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; +import java.util.concurrent.atomic.AtomicBoolean; public abstract class SearchForTestsTask extends Task.Backgroundable { @@ -101,14 +104,16 @@ public abstract class SearchForTestsTask extends Task.Backgroundable { try { mySocket = myServerSocket.accept(); final ExecutionException[] ex = new ExecutionException[1]; - DumbService.getInstance(getProject()).repeatUntilPassesInSmartMode(() -> { + Runnable runnable = () -> { try { search(); } catch (ExecutionException e) { ex[0] = e; } - }); + }; + //noinspection StatementWithEmptyBody + while (!runSmartModeReadActionWithWritePriority(runnable, new SensitiveProgressWrapper(indicator))); if (ex[0] != null) { logCantRunException(ex[0]); } @@ -124,6 +129,35 @@ public abstract class SearchForTestsTask extends Task.Backgroundable { } } + /** + * @return true if runnable has been executed with no write action interference and in "smart" mode + */ + private boolean runSmartModeReadActionWithWritePriority(@NotNull Runnable runnable, ProgressIndicator indicator) { + DumbService dumbService = DumbService.getInstance(myProject); + + indicator.checkCanceled(); + dumbService.waitForSmartMode(); + + AtomicBoolean dumb = new AtomicBoolean(); + boolean success = ProgressIndicatorUtils.runInReadActionWithWriteActionPriority(() -> { + if (myProject.isDisposed()) return; + + if (dumbService.isDumb()) { + dumb.set(true); + return; + } + + runnable.run(); + }, indicator); + if (dumb.get()) { + return false; + } + if (!success) { + ProgressIndicatorUtils.yieldToPendingWriteActions(); + } + return success; + } + protected void logCantRunException(ExecutionException e) throws ExecutionException { throw e; } diff --git a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java index 102fc8ae0334..752ead10a177 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java +++ b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -51,9 +51,7 @@ class RunConfigurationByRecordProvider implements ConfigurationByRecordProvider private void initRunConfigurationsMap() { RunManagerEx manager = RunManagerEx.getInstanceEx(myProject); - ConfigurationType[] types = manager.getConfigurationFactories(); - - for (ConfigurationType type : types) { + for (ConfigurationType type : manager.getConfigurationFactories()) { Map> structure = manager.getStructure(type); for (Map.Entry> e : structure.entrySet()) { for (RunnerAndConfigurationSettings settings : e.getValue()) { @@ -62,7 +60,6 @@ class RunConfigurationByRecordProvider implements ConfigurationByRecordProvider } } } - } diff --git a/java/idea-ui/src/com/intellij/ide/impl/NewProjectUtil.java b/java/idea-ui/src/com/intellij/ide/impl/NewProjectUtil.java index 62184dfc35d6..fb5ce69d4001 100644 --- a/java/idea-ui/src/com/intellij/ide/impl/NewProjectUtil.java +++ b/java/idea-ui/src/com/intellij/ide/impl/NewProjectUtil.java @@ -92,6 +92,7 @@ public class NewProjectUtil { } final ProjectBuilder projectBuilder = dialog.getProjectBuilder(); + LOG.debug("builder " + projectBuilder); try { File projectDir = new File(projectFilePath).getParentFile(); diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java index f7a0ffccbf5b..d6d35f6ee017 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java @@ -45,6 +45,7 @@ import com.intellij.platform.ProjectTemplate; import com.intellij.platform.ProjectTemplateEP; import com.intellij.platform.ProjectTemplatesFactory; import com.intellij.platform.templates.*; +import com.intellij.psi.impl.DebugUtil; import com.intellij.ui.CollectionListModel; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.ListSpeedSearch; @@ -123,6 +124,7 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D myTemplatesMap = new ConcurrentMultiMap<>(); final List groups = fillTemplatesMap(context); + LOG.debug("groups=" + groups); myProjectTypeList.setModel(new CollectionListModel<>(groups)); myProjectTypeList.setSelectionModel(new SingleSelectionModel()); @@ -232,6 +234,7 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D } final String groupId = PropertiesComponent.getInstance().getValue(PROJECT_WIZARD_GROUP); + LOG.debug("saved groupId=" + groupId); if (groupId != null) { TemplatesGroup group = ContainerUtil.find(groups, group1 -> groupId.equals(group1.getId())); if (group != null) { @@ -374,6 +377,9 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D if (group == null || group == myLastSelectedGroup) return; myLastSelectedGroup = group; PropertiesComponent.getInstance().setValue(PROJECT_WIZARD_GROUP, group.getId() ); + if (LOG.isDebugEnabled()) { + LOG.debug("projectTypeChanged: " + group.getId() + " " + DebugUtil.currentStackTrace()); + } ModuleBuilder groupModuleBuilder = group.getModuleBuilder(); mySettingsStep = null; @@ -644,6 +650,8 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D } ModuleBuilder builder = getSelectedBuilder(); + LOG.debug("builder=" + builder + "; template=" + template + "; group=" + getSelectedGroup() + "; groupIndex=" + myProjectTypeList.getMinSelectionIndex()); + myContext.setProjectBuilder(builder); if (builder != null) { myWizard.getSequence().setType(builder.getBuilderId()); diff --git a/java/idea-ui/src/com/intellij/jarRepository/JarRepositoryManager.java b/java/idea-ui/src/com/intellij/jarRepository/JarRepositoryManager.java index 1ee2fe74f79e..55e5fbbb9487 100644 --- a/java/idea-ui/src/com/intellij/jarRepository/JarRepositoryManager.java +++ b/java/idea-ui/src/com/intellij/jarRepository/JarRepositoryManager.java @@ -42,7 +42,6 @@ import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.util.PairProcessor; import com.intellij.util.Processor; import com.intellij.util.concurrency.SequentialTaskExecutor; import gnu.trove.THashMap; @@ -67,7 +66,6 @@ import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -96,13 +94,14 @@ public class JarRepositoryManager { return null; } - final List repositories = dialog.getRepositories(); final String coord = dialog.getCoordinateText(); final boolean attachSources = dialog.getAttachSources(); final boolean attachJavaDoc = dialog.getAttachJavaDoc(); final String copyTo = dialog.getDirectoryPath(); - final NewLibraryConfiguration config = resolveAndDownload(project, coord, attachSources, attachJavaDoc, copyTo, repositories); + final NewLibraryConfiguration config = resolveAndDownload( + project, coord, attachSources, attachJavaDoc, copyTo, RemoteRepositoryDescription.DEFAULT_REPOSITORIES + ); if (config == null) { Messages.showErrorDialog(parentComponent, "No files were downloaded for " + coord, CommonBundle.getErrorTitle()); } @@ -277,7 +276,7 @@ public class JarRepositoryManager { Notifications.Bus.notify(new Notification("Repository", title, sb.toString(), NotificationType.INFORMATION), project); } - public static void searchArtifacts(final Project project, String coord, final PairProcessor>, Boolean> resultProcessor) { + public static void searchArtifacts(final Project project, String coord, final Consumer>> resultProcessor) { if (coord == null || coord.length() == 0) { return; } @@ -291,30 +290,18 @@ public class JarRepositoryManager { ProgressManager.getInstance().run(new Task.Backgroundable(project, "Maven", false) { public void run(@NotNull ProgressIndicator indicator) { - String[] urls = MavenRepositoryServicesManager.getServiceUrls(); - boolean tooManyResults = false; - final AtomicBoolean proceedFlag = new AtomicBoolean(true); - - for (int i = 0, length = urls.length; i < length; i++) { - if (!proceedFlag.get()) break; - final List> resultList = new ArrayList<>(); - try { - String serviceUrl = urls[i]; - final List artifacts = MavenRepositoryServicesManager.findArtifacts(template, serviceUrl); - if (!artifacts.isEmpty()) { - if (!proceedFlag.get()) { - break; - } - final List repositories = MavenRepositoryServicesManager.getRepositories(serviceUrl); - Map map = new THashMap<>(); - for (RemoteRepositoryDescription repository : repositories) { - map.put(repository.getId(), repository); - } - for (RepositoryArtifactDescription artifact : artifacts) { - if (artifact == null) { - tooManyResults = true; + final List> resultList = new ArrayList<>(); + try { + for (String serviceUrl : MavenRepositoryServicesManager.getServiceUrls()) { + try { + final List artifacts = MavenRepositoryServicesManager.findArtifacts(template, serviceUrl); + if (!artifacts.isEmpty()) { + final List repositories = MavenRepositoryServicesManager.getRepositories(serviceUrl); + final Map map = new THashMap<>(); + for (RemoteRepositoryDescription repository : repositories) { + map.put(repository.getId(), repository); } - else { + for (RepositoryArtifactDescription artifact : artifacts) { final RemoteRepositoryDescription repository = map.get(artifact.getRepositoryId()); // if the artifact is provided by an unsupported repository just skip it // because it won't be resolved anyway @@ -324,38 +311,32 @@ public class JarRepositoryManager { } } } - } - catch (Exception e) { - LOG.error(e); - } - finally { - if (!proceedFlag.get()) { - break; + catch (Exception e) { + LOG.error(e); } - final Boolean aBoolean = i == length - 1 ? tooManyResults : null; - ApplicationManager.getApplication().invokeLater( - () -> proceedFlag.set(resultProcessor.process(resultList, aBoolean)), o -> !proceedFlag.get() - ); } } + finally { + ApplicationManager.getApplication().invokeLater(() -> resultProcessor.accept(resultList)); + } } }); } - public static void searchRepositories(final Project project, final Collection nexusUrls, final Processor> resultProcessor) { + public static void searchRepositories(final Project project, final Collection serviceUrls, final Processor> resultProcessor) { ProgressManager.getInstance().run(new Task.Backgroundable(project, "Maven", false) { public void run(@NotNull ProgressIndicator indicator) { final Ref> result = Ref.create(Collections.emptyList()); try { final ArrayList repoList = new ArrayList<>(); - for (String nexusUrl : nexusUrls) { + for (String url : serviceUrls) { final List repositories; try { - repositories = MavenRepositoryServicesManager.getRepositories(nexusUrl); + repositories = MavenRepositoryServicesManager.getRepositories(url); } catch (Exception ex) { - LOG.warn("Accessing Service at: " + nexusUrl, ex); + LOG.warn("Accessing Service at: " + url, ex); continue; } repoList.addAll(repositories); diff --git a/java/idea-ui/src/com/intellij/jarRepository/RepositoryAddLibraryAction.java b/java/idea-ui/src/com/intellij/jarRepository/RepositoryAddLibraryAction.java index ef1812cd53ac..49a33579308e 100644 --- a/java/idea-ui/src/com/intellij/jarRepository/RepositoryAddLibraryAction.java +++ b/java/idea-ui/src/com/intellij/jarRepository/RepositoryAddLibraryAction.java @@ -16,7 +16,7 @@ package com.intellij.jarRepository; import com.intellij.codeInspection.IntentionAndQuickFixAction; -import com.intellij.jarRepository.propertiesEditor.RepositoryLibraryPropertiesDialog; +import com.intellij.jarRepository.settings.RepositoryLibraryPropertiesDialog; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.module.Module; diff --git a/java/idea-ui/src/com/intellij/jarRepository/RepositoryAttachDialog.java b/java/idea-ui/src/com/intellij/jarRepository/RepositoryAttachDialog.java index e9ae84194e41..7065d88883c4 100644 --- a/java/idea-ui/src/com/intellij/jarRepository/RepositoryAttachDialog.java +++ b/java/idea-ui/src/com/intellij/jarRepository/RepositoryAttachDialog.java @@ -27,7 +27,6 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.ui.ValidationInfo; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; @@ -56,8 +55,10 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; public class RepositoryAttachDialog extends DialogWrapper { @NonNls private static final String PROPERTY_DOWNLOAD_TO_PATH = "Downloaded.Files.Path"; @@ -79,8 +80,7 @@ public class RepositoryAttachDialog extends DialogWrapper { private final JComboBox myCombobox; - private final Map> myCoordinates = ContainerUtil.newTroveMap(); - private final Map myRepositories = new TreeMap<>(); + private final Map myCoordinates = ContainerUtil.newTroveMap(); private final List myShownItems = ContainerUtil.newArrayList(); private final String myDefaultDownloadFolder; @@ -203,7 +203,9 @@ public class RepositoryAttachDialog extends DialogWrapper { main: for (String coordinate : myCoordinates.keySet()) { for (String part : parts) { - if (!StringUtil.containsIgnoreCase(coordinate, part)) continue main; + if (!StringUtil.containsIgnoreCase(coordinate, part)) { + continue main; + } } myShownItems.add(coordinate); } @@ -267,41 +269,22 @@ public class RepositoryAttachDialog extends DialogWrapper { private boolean performSearch() { final String text = getCoordinateText(); - if (StringUtil.isEmptyOrSpaces(text)) return false; - if (myCoordinates.containsKey(text)) return false; - if (myProgressIcon.isRunning()) return false; + if (myProgressIcon.isRunning() || StringUtil.isEmptyOrSpaces(text) || myCoordinates.containsKey(text)) { + return false; + } myProgressIcon.resume(); - JarRepositoryManager.searchArtifacts(myProject, text, (artifacts, tooMany) -> { + JarRepositoryManager.searchArtifacts(myProject, text, (pairs) -> { if (myProgressIcon.isDisposed()) { - return false; - } - if (tooMany != null) { - myProgressIcon.suspend(); // finished + return; } + myProgressIcon.suspend(); // finished final int prevSize = myCoordinates.size(); - for (Pair each : artifacts) { - myCoordinates.put(each.first.getGroupId() + ":" + each.first.getArtifactId() + ":" + each.first.getVersion(), each); - String url = each.second != null? each.second.getUrl() : null; - if (StringUtil.isNotEmpty(url) && !myRepositories.containsKey(url)) { - myRepositories.put(url, each.second); - } - } - String title = getTitle(); - String tooManyMessage = ": too many results found"; - if (tooMany != null) { - boolean alreadyThere = title.endsWith(tooManyMessage); - if (tooMany.booleanValue() && !alreadyThere) { - setTitle(title + tooManyMessage); - } - else if (!tooMany.booleanValue() && alreadyThere) { - setTitle(title.substring(0, title.length() - tooManyMessage.length())); - } + for (Pair pair : pairs) { + final RepositoryArtifactDescription artifact = pair.first; + myCoordinates.put(artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion(), artifact); } updateComboboxSelection(prevSize != myCoordinates.size()); - // tooMany != null on last call, so enable OK action to let - // local maven repo a chance even if all remote services failed - setOKActionEnabled(!myRepositories.isEmpty() || tooMany != null); - return true; + setOKActionEnabled(true); }); return true; } @@ -352,13 +335,6 @@ public class RepositoryAttachDialog extends DialogWrapper { return RepositoryAttachDialog.class.getName(); } - @NotNull - public List getRepositories() { - final Pair artifactAndRepo = myCoordinates.get(getCoordinateText()); - final RemoteRepositoryDescription repository = artifactAndRepo == null ? null : artifactAndRepo.second; - return repository != null ? Collections.singletonList(repository) : ContainerUtil.findAll(myRepositories.values(), Condition.NOT_NULL); - } - private boolean isValidCoordinateSelected() { final String text = getCoordinateText(); return text.split(":").length == 3; diff --git a/java/idea-ui/src/com/intellij/jarRepository/RepositoryLibrarySupportInModuleConfigurable.java b/java/idea-ui/src/com/intellij/jarRepository/RepositoryLibrarySupportInModuleConfigurable.java index bf6f57a1a1f4..b4a66448c248 100644 --- a/java/idea-ui/src/com/intellij/jarRepository/RepositoryLibrarySupportInModuleConfigurable.java +++ b/java/idea-ui/src/com/intellij/jarRepository/RepositoryLibrarySupportInModuleConfigurable.java @@ -16,7 +16,7 @@ package com.intellij.jarRepository; import com.intellij.framework.addSupport.FrameworkSupportInModuleConfigurable; -import com.intellij.jarRepository.propertiesEditor.RepositoryLibraryPropertiesEditor; +import com.intellij.jarRepository.settings.RepositoryLibraryPropertiesEditor; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModifiableModelsProvider; diff --git a/java/idea-ui/src/com/intellij/jarRepository/RepositoryLibraryWithDescriptionEditor.java b/java/idea-ui/src/com/intellij/jarRepository/RepositoryLibraryWithDescriptionEditor.java index ffee1c12e1a1..5c99fdc7928f 100644 --- a/java/idea-ui/src/com/intellij/jarRepository/RepositoryLibraryWithDescriptionEditor.java +++ b/java/idea-ui/src/com/intellij/jarRepository/RepositoryLibraryWithDescriptionEditor.java @@ -15,7 +15,7 @@ */ package com.intellij.jarRepository; -import com.intellij.jarRepository.propertiesEditor.RepositoryLibraryPropertiesDialog; +import com.intellij.jarRepository.settings.RepositoryLibraryPropertiesDialog; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.libraries.ui.LibraryEditorComponent; import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryEditor; diff --git a/java/idea-ui/src/com/intellij/jarRepository/propertiesEditor/RepositoryLibraryPropertiesEditor.form b/java/idea-ui/src/com/intellij/jarRepository/propertiesEditor/RepositoryLibraryPropertiesEditor.form deleted file mode 100644 index 12d569c4dc71..000000000000 --- a/java/idea-ui/src/com/intellij/jarRepository/propertiesEditor/RepositoryLibraryPropertiesEditor.form +++ /dev/null @@ -1,193 +0,0 @@ - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/java/idea-ui/src/com/intellij/jarRepository/propertiesEditor/RepositoryLibraryPropertiesDialog.java b/java/idea-ui/src/com/intellij/jarRepository/settings/RepositoryLibraryPropertiesDialog.java similarity index 97% rename from java/idea-ui/src/com/intellij/jarRepository/propertiesEditor/RepositoryLibraryPropertiesDialog.java rename to java/idea-ui/src/com/intellij/jarRepository/settings/RepositoryLibraryPropertiesDialog.java index d2d966ce58ef..601024874e7f 100644 --- a/java/idea-ui/src/com/intellij/jarRepository/propertiesEditor/RepositoryLibraryPropertiesDialog.java +++ b/java/idea-ui/src/com/intellij/jarRepository/settings/RepositoryLibraryPropertiesDialog.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.jarRepository.propertiesEditor; +package com.intellij.jarRepository.settings; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/propertiesEditor/RepositoryLibraryPropertiesEditor.form b/java/idea-ui/src/com/intellij/jarRepository/settings/RepositoryLibraryPropertiesEditor.form similarity index 97% rename from plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/propertiesEditor/RepositoryLibraryPropertiesEditor.form rename to java/idea-ui/src/com/intellij/jarRepository/settings/RepositoryLibraryPropertiesEditor.form index 5903bd9cafd7..cb1f7a895be3 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/propertiesEditor/RepositoryLibraryPropertiesEditor.form +++ b/java/idea-ui/src/com/intellij/jarRepository/settings/RepositoryLibraryPropertiesEditor.form @@ -1,5 +1,5 @@ -
+ @@ -134,7 +134,7 @@ @@ -148,7 +148,7 @@ diff --git a/java/idea-ui/src/com/intellij/jarRepository/propertiesEditor/RepositoryLibraryPropertiesEditor.java b/java/idea-ui/src/com/intellij/jarRepository/settings/RepositoryLibraryPropertiesEditor.java similarity index 99% rename from java/idea-ui/src/com/intellij/jarRepository/propertiesEditor/RepositoryLibraryPropertiesEditor.java rename to java/idea-ui/src/com/intellij/jarRepository/settings/RepositoryLibraryPropertiesEditor.java index da1a579d765e..d4765db18b1f 100644 --- a/java/idea-ui/src/com/intellij/jarRepository/propertiesEditor/RepositoryLibraryPropertiesEditor.java +++ b/java/idea-ui/src/com/intellij/jarRepository/settings/RepositoryLibraryPropertiesEditor.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.jarRepository.propertiesEditor; +package com.intellij.jarRepository.settings; import com.google.common.base.Strings; import com.intellij.jarRepository.JarRepositoryManager; diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java index 5c7a7a043632..5e99a4505e88 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java @@ -23,6 +23,7 @@ import com.intellij.facet.impl.ui.actions.AddFacetToModuleAction; import com.intellij.icons.AllIcons; import com.intellij.ide.IdeBundle; import com.intellij.ide.highlighter.ModuleFileType; +import com.intellij.ide.impl.FlattenModulesToggleAction; import com.intellij.ide.projectView.impl.ModuleGroup; import com.intellij.ide.projectView.impl.ModuleGroupingTreeHelper; import com.intellij.ide.util.projectWizard.ModuleBuilder; @@ -152,7 +153,10 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple final ArrayList result = super.createActions(fromPopup); if (fromPopup) { result.add(Separator.getInstance()); - result.add(new FlattenModulesAction()); + result.add(new FlattenModulesToggleAction(myProject, () -> true, () -> myFlattenModules, (value) -> { + myFlattenModules = value; + regroupModules(); + })); result.add(new HideGroupsAction()); addCollapseExpandActions(result); } @@ -761,31 +765,6 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple } } - private class FlattenModulesAction extends ToggleAction implements DumbAware { - public FlattenModulesAction() { - super(ProjectBundle.message("project.roots.flatten.modules.action.text"), - ProjectBundle.message("project.roots.flatten.modules.action.description"), AllIcons.ObjectBrowser.FlattenModules); - } - - @Override - public void update(@NotNull AnActionEvent e) { - super.update(e); - e.getPresentation().setEnabledAndVisible( - ModuleGrouperKt.isQualifiedModuleNamesEnabled() && !myContext.getModulesConfigurator().getModuleModel().hasModuleGroups()); - } - - @Override - public boolean isSelected(AnActionEvent e) { - return myFlattenModules; - } - - @Override - public void setSelected(AnActionEvent e, boolean state) { - myFlattenModules = state; - regroupModules(); - } - } - private class HideGroupsAction extends ToggleAction implements DumbAware { public HideGroupsAction() { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/SdkProjectStructureElement.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/SdkProjectStructureElement.java index bf9d7109fd26..18b765647698 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/SdkProjectStructureElement.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/SdkProjectStructureElement.java @@ -1,6 +1,7 @@ package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; import java.util.Collections; @@ -14,7 +15,12 @@ public class SdkProjectStructureElement extends ProjectStructureElement { public SdkProjectStructureElement(StructureConfigurableContext context, Sdk sdk) { super(context); - mySdk = sdk; + mySdk = getModifiableSdk(sdk); + } + + private Sdk getModifiableSdk(Sdk sdk) { + Sdk modifiableSdk = ProjectStructureConfigurable.getInstance(myContext.getProject()).getProjectJdksModel().getProjectSdks().get(sdk); + return modifiableSdk != null? modifiableSdk : sdk; } public Sdk getSdk() { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java index f3ba136b966e..cf7b6f9f7f76 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java @@ -18,11 +18,11 @@ package com.intellij.codeInsight; import com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalysis; import com.intellij.codeInspection.dataFlow.*; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.PsiMethodImpl; import com.intellij.psi.util.PsiUtil; import com.intellij.util.containers.ContainerUtil; +import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -162,8 +162,8 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager { } @Nullable - private PsiAnnotation createContractAnnotation(List contracts, boolean pure) { - return createContractAnnotation(myProject, pure, StringUtil.join(contracts, "; ")); + private PsiAnnotation createContractAnnotation(List contracts, boolean pure) { + return createContractAnnotation(myProject, pure, StreamEx.of(contracts).select(StandardMethodContract.class).joining("; ")); } @Nullable diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressWarningsFoldingBuilder.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressWarningsFoldingBuilder.java index 2bc5552d7791..214d5cf7712b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressWarningsFoldingBuilder.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressWarningsFoldingBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -29,7 +29,6 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphUtil.java index 9e271c08e503..0ed7bc667da0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphUtil.java @@ -46,14 +46,15 @@ public class JavaModuleGraphUtil { private JavaModuleGraphUtil() { } @Nullable - public static PsiJavaModule findDescriptorByElement(@NotNull PsiElement element) { - PsiFileSystemItem fsItem = element instanceof PsiFileSystemItem ? (PsiFileSystemItem)element : element.getContainingFile(); - return fsItem != null ? ModuleHighlightUtil.getModuleDescriptor(fsItem) : null; - } + public static PsiJavaModule findDescriptorByElement(@Nullable PsiElement element) { + if (element != null) { + PsiFileSystemItem fsItem = element instanceof PsiFileSystemItem ? (PsiFileSystemItem)element : element.getContainingFile(); + if (fsItem != null) { + return ModuleHighlightUtil.getModuleDescriptor(fsItem); + } + } - @Nullable - public static PsiJavaModule findDescriptorByModule(@Nullable Module module) { - return ModuleHighlightUtil.getModuleDescriptor(module); + return null; } @Nullable @@ -91,7 +92,7 @@ public class JavaModuleGraphUtil { private static List> findCycles(Project project) { Set projectModules = ContainerUtil.newHashSet(); for (Module module : ModuleManager.getInstance(project).getModules()) { - Collection files = FilenameIndex.getVirtualFilesByName(project, MODULE_INFO_FILE, module.getModuleScope(false)); + Collection files = FilenameIndex.getVirtualFilesByName(project, MODULE_INFO_FILE, module.getModuleScope()); if (files.size() > 1) return Collections.emptyList(); // aborts the process when there are incorrect modules in the project Optional.ofNullable(ContainerUtil.getFirstItem(files)) .map(PsiManager.getInstance(project)::findFile) @@ -145,7 +146,7 @@ public class JavaModuleGraphUtil { MultiMap relations = MultiMap.create(); Set transitiveEdges = ContainerUtil.newTroveSet(); for (Module module : ModuleManager.getInstance(project).getModules()) { - Collection files = FilenameIndex.getVirtualFilesByName(project, MODULE_INFO_FILE, module.getModuleScope(false)); + Collection files = FilenameIndex.getVirtualFilesByName(project, MODULE_INFO_FILE, module.getModuleScope()); Optional.ofNullable(ContainerUtil.getFirstItem(files)) .map(PsiManager.getInstance(project)::findFile) .map(f -> f instanceof PsiJavaFile ? ((PsiJavaFile)f).getModuleDeclaration() : null) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java index 26ff9d8148ce..dc4da03fa5c0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java @@ -79,21 +79,24 @@ public class ModuleHighlightUtil { return LightJavaModule.getModule(PsiManager.getInstance(project), classRoot); } } - - return null; } else { - return getModuleDescriptor(index.getModuleForFile(file)); + Module module = index.getModuleForFile(file); + if (module != null) { + boolean isTest = index.isInTestSourceContent(file); + List files = FilenameIndex.getVirtualFilesByName(project, MODULE_INFO_FILE, module.getModuleScope()).stream() + .filter(f -> index.isInTestSourceContent(f) == isTest) + .collect(Collectors.toList()); + if (files.size() == 1) { + PsiFile psiFile = PsiManager.getInstance(project).findFile(files.get(0)); + if (psiFile instanceof PsiJavaFile) { + return ((PsiJavaFile)psiFile).getModuleDeclaration(); + } + } + } } - } - static PsiJavaModule getModuleDescriptor(Module module) { - return Optional.ofNullable(module) - .map(m -> FilenameIndex.getVirtualFilesByName(module.getProject(), MODULE_INFO_FILE, m.getModuleScope(false))) - .map(c -> c.size() == 1 ? c.iterator().next() : null) - .map(f -> PsiManager.getInstance(module.getProject()).findFile(f)) - .map(f -> f instanceof PsiJavaFile ? ((PsiJavaFile)f).getModuleDeclaration() : null) - .orElse(null); + return null; } static HighlightInfo checkPackageStatement(@NotNull PsiPackageStatement statement, @NotNull PsiFile file, @Nullable PsiJavaModule module) { @@ -135,7 +138,7 @@ public class ModuleHighlightUtil { Module module = findModule(file); if (module != null) { Project project = file.getProject(); - Collection others = FilenameIndex.getVirtualFilesByName(project, MODULE_INFO_FILE, module.getModuleScope(false)); + Collection others = FilenameIndex.getVirtualFilesByName(project, MODULE_INFO_FILE, module.getModuleScope()); if (others.size() > 1) { String message = JavaErrorMessages.message("module.file.duplicate"); HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range(element)).descriptionAndTooltip(message).create(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergePackageAccessibilityStatementsFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergePackageAccessibilityStatementsFix.java index 0f771dce97b2..e7a23f336d3f 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergePackageAccessibilityStatementsFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergePackageAccessibilityStatementsFix.java @@ -88,13 +88,21 @@ public class MergePackageAccessibilityStatementsFix if (packageName != null) { final List moduleNames = statement.getModuleNames(); if (!moduleNames.isEmpty()) { + PsiPackageAccessibilityStatement targetStatement = null; for (PsiPackageAccessibilityStatement candidate : getStatements(javaModule, statement.getRole())) { - if (candidate != statement && - packageName.equals(candidate.getPackageName()) && - candidate.getModuleNames().iterator().hasNext()) { - return new MergePackageAccessibilityStatementsFix(statement, packageName, moduleNames, candidate); + if (candidate != statement && packageName.equals(candidate.getPackageName())) { + if (candidate.getModuleNames().isEmpty()) { + // merging with a statement that has no target modules is equivalent to deletion; deletion is a different fix + return null; + } + if (targetStatement == null) { + targetStatement = candidate; + } } } + if (targetStatement != null) { + return new MergePackageAccessibilityStatementsFix(statement, packageName, moduleNames, targetStatement); + } } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/HData.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/HData.java index f6f56da72dbc..6e77aa820636 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/HData.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/HData.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInspection.bytecodeAnalysis; +import com.intellij.util.ArrayFactory; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -90,6 +91,8 @@ final class HKey { * Represents a lattice product of a constant {@link #value} and all {@link #ids}. */ final class HComponent { + static final HComponent[] EMPTY_ARRAY = new HComponent[0]; + static final ArrayFactory ARRAY_FACTORY = count -> count == 0 ? EMPTY_ARRAY : new HComponent[count]; @NotNull Value value; @NotNull final HKey[] ids; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java index 79d8e339a27a..28b3753c2c42 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java @@ -15,7 +15,6 @@ */ package com.intellij.codeInspection.bytecodeAnalysis; -import com.intellij.util.ArrayFactory; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException; @@ -101,7 +100,6 @@ class ResultUtil { class HResultUtil { private static final HKey[] EMPTY_PRODUCT = new HKey[0]; - private static final ArrayFactory HCOMPONENT_ARRAY_FACTORY = count -> new HComponent[count]; private final ELattice lattice; final Value top; @@ -138,7 +136,7 @@ class HResultUtil { } HPending pending1 = (HPending) r1; HPending pending2 = (HPending) r2; - return new HPending(ArrayUtil.mergeArrays(pending1.delta, pending2.delta, HCOMPONENT_ARRAY_FACTORY)); + return new HPending(ArrayUtil.mergeArrays(pending1.delta, pending2.delta, HComponent.ARRAY_FACTORY)); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java index b4aa6c0f0f11..b78102907e7d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java @@ -39,8 +39,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import java.awt.*; public class CanBeFinalInspection extends GlobalJavaBatchInspectionTool { @@ -70,34 +68,19 @@ public class CanBeFinalInspection extends GlobalJavaBatchInspectionTool { myReportClassesCheckbox = new JCheckBox(InspectionsBundle.message("inspection.can.be.final.option")); myReportClassesCheckbox.setSelected(REPORT_CLASSES); - myReportClassesCheckbox.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - REPORT_CLASSES = myReportClassesCheckbox.isSelected(); - } - }); + myReportClassesCheckbox.getModel().addItemListener(e -> REPORT_CLASSES = myReportClassesCheckbox.isSelected()); gc.gridy = 0; add(myReportClassesCheckbox, gc); myReportMethodsCheckbox = new JCheckBox(InspectionsBundle.message("inspection.can.be.final.option1")); myReportMethodsCheckbox.setSelected(REPORT_METHODS); - myReportMethodsCheckbox.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - REPORT_METHODS = myReportMethodsCheckbox.isSelected(); - } - }); + myReportMethodsCheckbox.getModel().addItemListener(e -> REPORT_METHODS = myReportMethodsCheckbox.isSelected()); gc.gridy++; add(myReportMethodsCheckbox, gc); myReportFieldsCheckbox = new JCheckBox(InspectionsBundle.message("inspection.can.be.final.option2")); myReportFieldsCheckbox.setSelected(REPORT_FIELDS); - myReportFieldsCheckbox.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - REPORT_FIELDS = myReportFieldsCheckbox.isSelected(); - } - }); + myReportFieldsCheckbox.getModel().addItemListener(e -> REPORT_FIELDS = myReportFieldsCheckbox.isSelected()); gc.weighty = 1; gc.gridy++; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractChecker.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractChecker.java index e6a3436fa072..c3ebffab8cdd 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractChecker.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractChecker.java @@ -17,6 +17,7 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.value.*; +import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType; import com.intellij.psi.*; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -31,18 +32,18 @@ import java.util.Set; */ class ContractChecker extends DataFlowRunner { private final PsiMethod myMethod; - private final MethodContract myContract; + private final StandardMethodContract myContract; private final Set myViolations = ContainerUtil.newHashSet(); private final Set myNonViolations = ContainerUtil.newHashSet(); private final Set myFailures = ContainerUtil.newHashSet(); - private ContractChecker(PsiMethod method, MethodContract contract) { + private ContractChecker(PsiMethod method, StandardMethodContract contract) { super(false, true); myMethod = method; myContract = contract; } - static Map checkContractClause(PsiMethod method, MethodContract contract, boolean ignoreAssertions) { + static Map checkContractClause(PsiMethod method, StandardMethodContract contract, boolean ignoreAssertions) { PsiCodeBlock body = method.getBody(); if (body == null) return Collections.emptyMap(); @@ -58,7 +59,7 @@ class ContractChecker extends DataFlowRunner { if (comparisonValue != null) { boolean negated = constraint.shouldUseNonEqComparison(); DfaVariableValue dfaParam = factory.getVarFactory().createVariableValue(parameters[i], false); - initialState.applyCondition(factory.getRelationFactory().createRelation(dfaParam, comparisonValue, JavaTokenType.EQEQ, negated)); + initialState.applyCondition(factory.createCondition(dfaParam, RelationType.equivalence(!negated), comparisonValue)); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java index 24f8357459fb..de08c1bc2d3d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -43,7 +43,7 @@ public class ContractInference { public static final int MAX_CONTRACT_COUNT = 10; @NotNull - public static List inferContracts(@NotNull PsiMethodImpl method) { + public static List inferContracts(@NotNull PsiMethodImpl method) { if (!InferenceFromSourceUtil.shouldInferFromSource(method)) { return Collections.emptyList(); } @@ -51,22 +51,22 @@ public class ContractInference { return CachedValuesManager.getCachedValue(method, () -> { MethodData data = ContractInferenceIndexKt.getIndexedData(method); List preContracts = data == null ? Collections.emptyList() : data.getContracts(); - List result = RecursionManager.doPreventingRecursion(method, true, () -> postProcessContracts(method, data, preContracts)); + List result = RecursionManager.doPreventingRecursion(method, true, () -> postProcessContracts(method, data, preContracts)); if (result == null) result = Collections.emptyList(); return CachedValueProvider.Result.create(result, method, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); }); } @NotNull - private static List postProcessContracts(@NotNull PsiMethodImpl method, MethodData data, List rawContracts) { - List contracts = ContainerUtil.concat(rawContracts, c -> c.toContracts(method, data.methodBody(method))); + private static List postProcessContracts(@NotNull PsiMethodImpl method, MethodData data, List rawContracts) { + List contracts = ContainerUtil.concat(rawContracts, c -> c.toContracts(method, data.methodBody(method))); if (contracts.isEmpty()) return Collections.emptyList(); final PsiType returnType = method.getReturnType(); if (returnType != null && !(returnType instanceof PsiPrimitiveType)) { contracts = boxReturnValues(contracts); } - List compatible = ContainerUtil.filter(contracts, contract -> isContractCompatibleWithMethod(method, returnType, contract)); + List compatible = ContainerUtil.filter(contracts, contract -> isContractCompatibleWithMethod(method, returnType, contract)); if (compatible.size() > MAX_CONTRACT_COUNT) { LOG.debug("Too many contracts for " + PsiUtil.getMemberQualifiedName(method) + ", shrinking the list"); return compatible.subList(0, MAX_CONTRACT_COUNT); @@ -74,14 +74,14 @@ public class ContractInference { return compatible; } - private static boolean isContractCompatibleWithMethod(@NotNull PsiMethod method, PsiType returnType, MethodContract contract) { + private static boolean isContractCompatibleWithMethod(@NotNull PsiMethod method, PsiType returnType, StandardMethodContract contract) { if (hasContradictoryExplicitParameterNullity(method, contract)) return false; if (isReturnNullitySpecifiedExplicitly(method, contract)) return false; if (isContradictingExplicitNullableReturn(method, contract)) return false; return InferenceFromSourceUtil.isReturnTypeCompatible(returnType, contract.returnValue); } - private static boolean hasContradictoryExplicitParameterNullity(@NotNull PsiMethod method, MethodContract contract) { + private static boolean hasContradictoryExplicitParameterNullity(@NotNull PsiMethod method, StandardMethodContract contract) { for (int i = 0; i < contract.arguments.length; i++) { if (contract.arguments[i] == NULL_VALUE && NullableNotNullManager.isNotNull(method.getParameterList().getParameters()[i])) { return true; @@ -90,13 +90,13 @@ public class ContractInference { return false; } - private static boolean isContradictingExplicitNullableReturn(@NotNull PsiMethod method, MethodContract contract) { + private static boolean isContradictingExplicitNullableReturn(@NotNull PsiMethod method, StandardMethodContract contract) { return contract.returnValue == NOT_NULL_VALUE && Arrays.stream(contract.arguments).allMatch(c -> c == ANY_VALUE) && NullableNotNullManager.getInstance(method.getProject()).isNullable(method, false); } - private static boolean isReturnNullitySpecifiedExplicitly(@NotNull PsiMethod method, MethodContract contract) { + private static boolean isReturnNullitySpecifiedExplicitly(@NotNull PsiMethod method, StandardMethodContract contract) { if (contract.returnValue != NOT_NULL_VALUE && contract.returnValue != NULL_VALUE) { return false; // spare expensive nullity check } @@ -104,10 +104,10 @@ public class ContractInference { } @NotNull - private static List boxReturnValues(List contracts) { + private static List boxReturnValues(List contracts) { return ContainerUtil.mapNotNull(contracts, contract -> { if (contract.returnValue == FALSE_VALUE || contract.returnValue == TRUE_VALUE) { - return new MethodContract(contract.arguments, NOT_NULL_VALUE); + return new StandardMethodContract(contract.arguments, NOT_NULL_VALUE); } return contract; }); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInferenceInterpreter.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInferenceInterpreter.java index 111fb4442ea1..ada322f9f016 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInferenceInterpreter.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInferenceInterpreter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -65,7 +65,7 @@ class ContractInferenceInterpreter { if (result != null) return result; } - return visitStatements(singletonList(MethodContract.createConstraintArray(getParameters().size())), statements); + return visitStatements(singletonList(StandardMethodContract.createConstraintArray(getParameters().size())), statements); } @Nullable @@ -168,11 +168,11 @@ class ContractInferenceInterpreter { int paramIndex = resolveParameter(expr); if (paramIndex >= 0) { - List result = ContainerUtil.newArrayList(); + List result = ContainerUtil.newArrayList(); for (ValueConstraint[] state : states) { if (state[paramIndex] != ANY_VALUE) { // the second 'o' reference in cases like: if (o != null) return o; - result.add(new MethodContract(state, state[paramIndex])); + result.add(new StandardMethodContract(state, state[paramIndex])); } else if (JavaTokenType.BOOLEAN_KEYWORD == getPrimitiveParameterType(paramIndex)) { // if (boolValue) ... ContainerUtil.addIfNotNull(result, contractWithConstraint(state, paramIndex, TRUE_VALUE, TRUE_VALUE)); @@ -188,7 +188,7 @@ class ContractInferenceInterpreter { @NotNull private List visitPolyadic(List states, @NotNull LighterASTNode expr) { if (firstChildOfType(myTree, expr, JavaTokenType.PLUS) != null) { - return asPreContracts(ContainerUtil.map(states, s -> new MethodContract(s, NOT_NULL_VALUE))); + return asPreContracts(ContainerUtil.map(states, s -> new StandardMethodContract(s, NOT_NULL_VALUE))); } List operands = getExpressionChildren(myTree, expr); @@ -206,22 +206,22 @@ class ContractInferenceInterpreter { } @NotNull - private static List asPreContracts(List contracts) { + private static List asPreContracts(List contracts) { return ContainerUtil.map(contracts, KnownContract::new); } @Nullable - private static MethodContract contractWithConstraint(ValueConstraint[] state, - int parameter, ValueConstraint paramConstraint, - ValueConstraint returnValue) { + private static StandardMethodContract contractWithConstraint(ValueConstraint[] state, + int parameter, ValueConstraint paramConstraint, + ValueConstraint returnValue) { ValueConstraint[] newState = withConstraint(state, parameter, paramConstraint); - return newState == null ? null : new MethodContract(newState, returnValue); + return newState == null ? null : new StandardMethodContract(newState, returnValue); } - private List visitEqualityComparison(List states, - LighterASTNode op1, - LighterASTNode op2, - boolean equality) { + private List visitEqualityComparison(List states, + LighterASTNode op1, + LighterASTNode op2, + boolean equality) { int parameter = resolveParameter(op1); ValueConstraint constraint = getLiteralConstraint(op2); if (parameter < 0 || constraint == null) { @@ -229,7 +229,7 @@ class ContractInferenceInterpreter { constraint = getLiteralConstraint(op1); } if (parameter >= 0 && constraint != null) { - List result = ContainerUtil.newArrayList(); + List result = ContainerUtil.newArrayList(); for (ValueConstraint[] state : states) { if (constraint == NOT_NULL_VALUE) { if (getPrimitiveParameterType(parameter) == null) { @@ -253,13 +253,13 @@ class ContractInferenceInterpreter { return primitive == null ? null : primitive.getTokenType(); } - static List toContracts(List states, ValueConstraint constraint) { - return ContainerUtil.map(states, state -> new MethodContract(state, constraint)); + static List toContracts(List states, ValueConstraint constraint) { + return ContainerUtil.map(states, state -> new StandardMethodContract(state, constraint)); } - private List visitLogicalOperation(List operands, boolean conjunction, List states) { + private List visitLogicalOperation(List operands, boolean conjunction, List states) { ValueConstraint breakValue = conjunction ? FALSE_VALUE : TRUE_VALUE; - List finalStates = ContainerUtil.newArrayList(); + List finalStates = ContainerUtil.newArrayList(); for (LighterASTNode operand : operands) { List opResults = visitExpression(states, operand); finalStates.addAll(ContainerUtil.filter(knownContracts(opResults), contract -> contract.returnValue == breakValue)); @@ -269,7 +269,7 @@ class ContractInferenceInterpreter { return finalStates; } - private static List knownContracts(List values) { + private static List knownContracts(List values) { return ContainerUtil.mapNotNull(values, pc -> pc instanceof KnownContract ? ((KnownContract)pc).getContract() : null); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInspection.java index ae986149dc20..f59d88660ee4 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInspection.java @@ -39,7 +39,7 @@ public class ContractInspection extends BaseJavaBatchLocalInspectionTool { @Override public void visitMethod(PsiMethod method) { - for (MethodContract contract : ControlFlowAnalyzer.getMethodContracts(method)) { + for (StandardMethodContract contract : ControlFlowAnalyzer.getMethodContracts(method)) { Map errors = ContractChecker.checkContractClause(method, contract, false); for (Map.Entry entry : errors.entrySet()) { PsiElement element = entry.getKey(); @@ -78,16 +78,16 @@ public class ContractInspection extends BaseJavaBatchLocalInspectionTool { @Nullable public static String checkContract(PsiMethod method, String text) { - List contracts; + List contracts; try { - contracts = MethodContract.parseContract(text); + contracts = StandardMethodContract.parseContract(text); } - catch (MethodContract.ParseException e) { + catch (StandardMethodContract.ParseException e) { return e.getMessage(); } int paramCount = method.getParameterList().getParametersCount(); for (int i = 0; i < contracts.size(); i++) { - MethodContract contract = contracts.get(i); + StandardMethodContract contract = contracts.get(i); if (contract.arguments.length != paramCount) { return "Method takes " + paramCount + " parameters, while contract clause number " + (i + 1) + " expects " + contract.arguments.length; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index e79d900976d9..c659ad95d059 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.ExceptionUtil; import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.value.*; +import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.registry.Registry; @@ -27,9 +28,13 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.*; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.FList; import com.siyeh.ig.numeric.UnnecessaryExplicitNumericCastInspection; +import com.siyeh.ig.psiutils.CountingLoop; +import com.siyeh.ig.psiutils.ExpressionUtils; +import com.siyeh.ig.psiutils.VariableAccessUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -463,6 +468,8 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { }); } + addCountingLoopBound(statement); + PsiExpression condition = statement.getCondition(); if (condition != null) { condition.accept(this); @@ -496,6 +503,46 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { } } + /** + * Add known-to-be-true condition inside counting loop, effectively converting + * {@code for(int i=origin; i=origin && i + * Does nothing if the statement is not a counting loop. + * + * @param statement counting loop candidate. + */ + private void addCountingLoopBound(PsiForStatement statement) { + CountingLoop loop = CountingLoop.from(statement); + if (loop == null) return; + PsiLocalVariable counter = loop.getCounter(); + if (loop.isIncluding() && !(PsiType.LONG.equals(counter.getType()) && PsiType.INT.equals(loop.getBound().getType()))) { + Object bound = ExpressionUtils.computeConstantExpression(loop.getBound()); + // could be for(int i=0; i<=Integer.MAX_VALUE; i++) which will overflow: conservatively skip this + if (!(bound instanceof Number)) return; + if (bound.equals(Long.MAX_VALUE) || bound.equals(Integer.MAX_VALUE)) return; + } + PsiExpression initializer = loop.getInitializer(); + if (!PsiType.INT.equals(initializer.getType()) && !PsiType.LONG.equals(initializer.getType())) return; + DfaValue origin = null; + Object initialValue = ExpressionUtils.computeConstantExpression(initializer); + if (initialValue instanceof Number) { + origin = myFactory.getConstFactory().createFromValue(initialValue, initializer.getType(), null); + } + else if (initializer instanceof PsiReferenceExpression) { + PsiVariable initialVariable = ObjectUtils.tryCast(((PsiReferenceExpression)initializer).resolve(), PsiVariable.class); + if ((initialVariable instanceof PsiLocalVariable || initialVariable instanceof PsiParameter) + && !VariableAccessUtils.variableIsAssigned(initialVariable, statement.getBody())) { + origin = myFactory.getVarFactory().createVariableValue(initialVariable, false); + } + } + if (origin == null || VariableAccessUtils.variableIsAssigned(counter, statement.getBody())) return; + addInstruction(new PushInstruction(myFactory.getVarFactory().createVariableValue(counter, false), null)); + addInstruction(new PushInstruction(origin, null)); + addInstruction(new BinopInstruction(JavaTokenType.LT, null, myProject)); + addInstruction(new ConditionalGotoInstruction(getEndOffset(statement), false, null)); + } + @Override public void visitIfStatement(PsiIfStatement statement) { startElement(statement); @@ -741,8 +788,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState state, InstructionVisitor visitor) { DfaValue value = state.pop(); DfaValueFactory factory = runner.getFactory(); - if (state.applyCondition( - factory.getRelationFactory().createRelation(value, factory.getConstFactory().getNull(), JavaTokenType.EQEQ, true))) { + if (state.applyCondition(factory.createCondition(value, RelationType.NE, factory.getConstFactory().getNull()))) { return nextInstruction(runner, state); } if (visitor instanceof StandardInstructionVisitor) { @@ -1292,9 +1338,10 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { } addConditionalRuntimeThrow(); - List contracts = method instanceof PsiMethod ? getMethodCallContracts((PsiMethod)method, expression) : Collections.emptyList(); + List contracts = + method instanceof PsiMethod ? getMethodCallContracts((PsiMethod)method, expression) : Collections.emptyList(); addInstruction(new MethodCallInstruction(expression, myFactory.createValue(expression), contracts)); - if (contracts.stream().anyMatch(c -> c.returnValue == MethodContract.ValueConstraint.THROW_EXCEPTION)) { + if (contracts.stream().anyMatch(c -> c.getReturnValue() == MethodContract.ValueConstraint.THROW_EXCEPTION)) { // if a contract resulted in 'fail', handle it addInstruction(new DupInstruction()); addInstruction(new PushInstruction(myFactory.getConstFactory().getContractFail(), null)); @@ -1329,12 +1376,13 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { finishElement(expression); } - private static List getMethodCallContracts(@NotNull final PsiMethod method, @NotNull PsiMethodCallExpression call) { + private static List getMethodCallContracts(@NotNull final PsiMethod method, + @NotNull PsiMethodCallExpression call) { List contracts = HardcodedContracts.getHardcodedContracts(method, call); return !contracts.isEmpty() ? contracts : getMethodContracts(method); } - public static List getMethodContracts(@NotNull final PsiMethod method) { + public static List getMethodContracts(@NotNull final PsiMethod method) { return CachedValuesManager.getCachedValue(method, () -> { final PsiAnnotation contractAnno = findContractAnnotation(method); if (contractAnno != null) { @@ -1342,15 +1390,16 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { if (text != null) { try { final int paramCount = method.getParameterList().getParametersCount(); - List applicable = ContainerUtil.filter(MethodContract.parseContract(text), - contract -> contract.arguments.length == paramCount); + List applicable = ContainerUtil.filter(StandardMethodContract.parseContract(text), + contract -> contract.arguments.length == paramCount); return CachedValueProvider.Result.create(applicable, contractAnno, method, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); } catch (Exception ignored) { } } } - return CachedValueProvider.Result.create(Collections.emptyList(), method, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); + return CachedValueProvider.Result + .create(Collections.emptyList(), method, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); }); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java index c5a3295229a7..159b7282c83a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java @@ -17,6 +17,7 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet; import com.intellij.codeInspection.dataFlow.value.*; +import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType; import com.intellij.psi.PsiMethodCallExpression; import com.intellij.psi.PsiType; import com.intellij.util.ArrayUtil; @@ -29,7 +30,6 @@ import java.util.Collections; import java.util.List; import static com.intellij.psi.CommonClassNames.*; -import static com.intellij.psi.JavaTokenType.*; import static com.siyeh.ig.callMatcher.CallMatcher.*; /** @@ -84,10 +84,10 @@ public class CustomMethodHandlers { if (leftConst != null && rightConst != null) { return singleResult(memState, factory.getBoolean(ends ? leftConst.endsWith(rightConst) : leftConst.startsWith(rightConst))); } - DfaValue leftLength = memState.getStringLength(qualifier); - DfaValue rightLength = memState.getStringLength(arg); - DfaRelationValue trueRelation = factory.getRelationFactory().createRelation(leftLength, rightLength, GE, false); - DfaRelationValue falseRelation = factory.getRelationFactory().createRelation(leftLength, rightLength, LT, false); + DfaValue leftLength = factory.createStringLength(qualifier); + DfaValue rightLength = factory.createStringLength(arg); + DfaValue trueRelation = factory.createCondition(leftLength, RelationType.GE, rightLength); + DfaValue falseRelation = factory.createCondition(leftLength, RelationType.LT, rightLength); return applyCondition(memState, trueRelation, DfaUnknownValue.getInstance(), falseRelation, factory.getBoolean(false)); } @@ -103,30 +103,30 @@ public class CustomMethodHandlers { if (leftConst != null && rightConst != null) { return singleResult(memState, factory.getBoolean(ignoreCase ? leftConst.equalsIgnoreCase(rightConst) : leftConst.equals(rightConst))); } - DfaValue leftLength = memState.getStringLength(qualifier); - DfaValue rightLength = memState.getStringLength(arg); - DfaRelationValue trueRelation = factory.getRelationFactory().createRelation(leftLength, rightLength, EQ, false); - DfaRelationValue falseRelation = factory.getRelationFactory().createRelation(leftLength, rightLength, NE, false); + DfaValue leftLength = factory.createStringLength(qualifier); + DfaValue rightLength = factory.createStringLength(arg); + DfaValue trueRelation = factory.createCondition(leftLength, RelationType.EQ, rightLength); + DfaValue falseRelation = factory.createCondition(leftLength, RelationType.NE, rightLength); return applyCondition(memState, trueRelation, DfaUnknownValue.getInstance(), falseRelation, factory.getBoolean(false)); } private static List stringIndexOf(DfaValue qualifier, DfaMemoryState memState, DfaValueFactory factory) { - DfaValue length = memState.getStringLength(qualifier); + DfaValue length = factory.createStringLength(qualifier); LongRangeSet range = memState.getRange(length); long maxLen = range == null || range.isEmpty() ? Integer.MAX_VALUE : range.max(); return singleResult(memState, factory.getRangeFactory().create(LongRangeSet.range(-1, maxLen - 1))); } private static List stringIsEmpty(DfaValue qualifier, DfaMemoryState memState, DfaValueFactory factory) { - DfaValue length = memState.getStringLength(qualifier); + DfaValue length = factory.createStringLength(qualifier); if (length == DfaUnknownValue.getInstance()) { return singleResult(memState, DfaUnknownValue.getInstance()); } DfaConstValue zero = factory.getConstFactory().createFromValue(0, PsiType.INT, null); - DfaRelationValue trueRelation = factory.getRelationFactory().createRelation(length, zero, EQEQ, false); - DfaRelationValue falseRelation = factory.getRelationFactory().createRelation(length, zero, NE, false); + DfaValue trueRelation = factory.createCondition(length, RelationType.EQ, zero); + DfaValue falseRelation = factory.createCondition(length, RelationType.NE, zero); return applyCondition(memState, trueRelation, factory.getBoolean(true), falseRelation, factory.getBoolean(false)); } @@ -156,17 +156,17 @@ public class CustomMethodHandlers { @NotNull private static List applyCondition(DfaMemoryState memState, - DfaRelationValue trueRelation, + DfaValue trueCondition, DfaValue trueResult, - DfaRelationValue falseRelation, + DfaValue falseCondition, DfaValue falseResult) { DfaMemoryState falseState = memState.createCopy(); List result = new ArrayList<>(2); - if (memState.applyCondition(trueRelation)) { + if (memState.applyCondition(trueCondition)) { memState.push(trueResult); result.add(memState); } - if (falseState.applyCondition(falseRelation)) { + if (falseState.applyCondition(falseCondition)) { falseState.push(falseResult); result.add(falseState); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java index 41864a95ad7e..112d5f47a3c3 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java @@ -405,7 +405,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { for (PsiCall call : visitor.getAlwaysFailingCalls()) { PsiMethod method = call.resolveMethod(); if (method != null && reportedAnchors.add(call)) { - holder.registerProblem(getElementToHighlight(call), "The call to #ref always fails, according to its method contracts"); + holder.registerProblem(getElementToHighlight(call), "The call to '#ref' always fails, according to its method contracts"); } } } @@ -1028,7 +1028,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { } private static boolean isNonTrivialFailingContract(MethodContract contract) { - return contract.returnValue == MethodContract.ValueConstraint.THROW_EXCEPTION && !contract.isTrivial(); + return contract.getReturnValue() == MethodContract.ValueConstraint.THROW_EXCEPTION && !contract.isTrivial(); } @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java index 43ef79454fdc..8c92f05636cd 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java @@ -48,17 +48,15 @@ public interface DfaMemoryState { boolean applyInstanceofOrNull(@NotNull DfaRelationValue dfaCond); - void applyIsPresentCheck(boolean present, DfaValue qualifier); - boolean applyCondition(DfaValue dfaCond); + boolean applyContractCondition(DfaValue dfaCond); + ThreeState checkOptional(DfaValue value); @Nullable LongRangeSet getRange(DfaValue value); - DfaValue getStringLength(DfaValue value); - void flushFields(); void flushVariable(DfaVariableValue variable); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index 81990047f9df..bf9a117fdfc3 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -26,18 +26,22 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet; import com.intellij.codeInspection.dataFlow.value.*; +import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.UnorderedPair; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.PsiEnumConstant; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiPrimitiveType; +import com.intellij.psi.PsiType; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.ThreeState; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Stack; +import com.siyeh.ig.psiutils.MethodUtils; import gnu.trove.*; import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; @@ -265,7 +269,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { setVariableState(var, withValueNullability(value, getVariableState(var).withValue(value))); if (value instanceof DfaTypeValue) { - DfaRelationValue dfaInstanceof = myFactory.getRelationFactory().createRelation(var, value, JavaTokenType.INSTANCEOF_KEYWORD, false); + DfaRelationValue dfaInstanceof = myFactory.getRelationFactory().createRelation(var, RelationType.IS, value); if (((DfaTypeValue)value).isNotNull()) { applyCondition(dfaInstanceof); } else { @@ -273,7 +277,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } } else { - DfaRelationValue dfaEqual = myFactory.getRelationFactory().createRelation(var, value, JavaTokenType.EQEQ, false); + DfaRelationValue dfaEqual = myFactory.getRelationFactory().createRelation(var, RelationType.EQ, value); if (dfaEqual == null) return; applyCondition(dfaEqual); @@ -283,7 +287,8 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } if (getVariableState(var).isNotNull()) { - applyCondition(compareToNull(var, true)); + DfaConstValue dfaNull = myFactory.getConstFactory().getNull(); + applyCondition(myFactory.getRelationFactory().createRelation(var, RelationType.NE, dfaNull)); } } @@ -650,8 +655,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { return false; } - @Override - public void applyIsPresentCheck(boolean present, DfaValue qualifier) { + private void applyIsPresentCheck(boolean present, DfaValue qualifier) { if (qualifier instanceof DfaVariableValue && !isUnknownState(qualifier)) { setVariableState((DfaVariableValue)qualifier, getVariableState((DfaVariableValue)qualifier).withOptionalPresense(present)); } @@ -663,7 +667,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } } - public boolean applyRange(LongRangeSet range, DfaVariableValue target) { + boolean applyRange(LongRangeSet range, DfaVariableValue target) { if (!isUnknownState(target) && range != null) { DfaVariableState state = getVariableState(target); LongRangeSet oldRange = state.getRange(); @@ -688,6 +692,21 @@ public class DfaMemoryStateImpl implements DfaMemoryState { return value; } + @Override + public boolean applyContractCondition(DfaValue condition) { + if (condition instanceof DfaRelationValue) { + DfaRelationValue relation = (DfaRelationValue)condition; + if (relation.isEquality() && + relation.getRightOperand() == myFactory.getConstFactory().getNull() && + (relation.getLeftOperand() instanceof DfaUnknownValue || + (relation.getLeftOperand() instanceof DfaVariableValue && + getVariableState((DfaVariableValue)relation.getLeftOperand()).getNullability() == Nullness.UNKNOWN))) { + markEphemeral(); + } + } + return applyCondition(condition); + } + @Override public boolean applyCondition(DfaValue dfaCond) { if (dfaCond instanceof DfaUnknownValue) return true; @@ -696,14 +715,16 @@ public class DfaMemoryStateImpl implements DfaMemoryState { boolean isNegated = dfaVar.isNegated(); DfaVariableValue dfaNormalVar = isNegated ? dfaVar.createNegated() : dfaVar; final DfaValue boxedTrue = myFactory.getBoxedFactory().createBoxed(myFactory.getConstFactory().getTrue()); - return applyRelationCondition(myFactory.getRelationFactory().createRelation(dfaNormalVar, boxedTrue, JavaTokenType.EQEQ, isNegated)); + return applyRelationCondition( + myFactory.getRelationFactory().createRelation(dfaNormalVar, RelationType.equivalence(!isNegated), boxedTrue)); } if (dfaCond instanceof DfaVariableValue) { DfaVariableValue dfaVar = (DfaVariableValue)dfaCond; boolean isNegated = dfaVar.isNegated(); DfaVariableValue dfaNormalVar = isNegated ? dfaVar.createNegated() : dfaVar; DfaConstValue dfaTrue = myFactory.getConstFactory().getTrue(); - return applyRelationCondition(myFactory.getRelationFactory().createRelation(dfaNormalVar, dfaTrue, JavaTokenType.EQEQ, isNegated)); + return applyRelationCondition( + myFactory.getRelationFactory().createRelation(dfaNormalVar, RelationType.equivalence(!isNegated), dfaTrue)); } if (dfaCond instanceof DfaConstValue) { @@ -719,13 +740,12 @@ public class DfaMemoryStateImpl implements DfaMemoryState { DfaValue dfaLeft = dfaRelation.getLeftOperand(); DfaValue dfaRight = dfaRelation.getRightOperand(); if (dfaLeft instanceof DfaUnknownValue || dfaRight instanceof DfaUnknownValue) return true; - - boolean isNegated = dfaRelation.isNegated(); + RelationType relationType = dfaRelation.getRelation(); if (dfaLeft instanceof DfaVariableValue) { LongRangeSet right = getRange(dfaRight); if (right != null) { - if (!applyRange(right.fromRelation(dfaRelation.getComparisonOperation()), (DfaVariableValue)dfaLeft)) { + if (!applyRange(right.fromRelation(relationType), (DfaVariableValue)dfaLeft)) { return false; } } @@ -733,15 +753,23 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (dfaRight instanceof DfaVariableValue) { LongRangeSet left = getRange(dfaLeft); if (left != null) { - if (!applyRange(left.fromRelation(DfaRelationValue.getSymmetricOperation(dfaRelation.getComparisonOperation())), - (DfaVariableValue)dfaRight)) { + if (!applyRange(left.fromRelation(relationType.getFlipped()), (DfaVariableValue)dfaRight)) { return false; } } } - if (dfaLeft instanceof DfaTypeValue && ((DfaTypeValue)dfaLeft).isNotNull() && dfaRight == myFactory.getConstFactory().getNull()) { - return isNegated; + if (dfaRight instanceof DfaOptionalValue && (relationType == RelationType.IS || relationType == RelationType.IS_NOT)) { + ThreeState state = checkOptional(dfaLeft); + boolean present = ((DfaOptionalValue)dfaRight).isPresent(); + if (relationType == RelationType.IS_NOT) { + present = !present; + } + if (state == ThreeState.UNSURE) { + applyIsPresentCheck(present, dfaLeft); + return true; + } + return state == ThreeState.fromBoolean(present); } if (dfaRight instanceof DfaTypeValue) { @@ -749,42 +777,43 @@ public class DfaMemoryStateImpl implements DfaMemoryState { DfaVariableValue dfaVar = (DfaVariableValue)dfaLeft; if (isUnknownState(dfaVar)) return true; - if (!dfaRelation.isInstanceOf()) { - if (((DfaTypeValue)dfaRight).isNotNull() && isNull(dfaVar)) { - return isNegated; + DfaTypeValue typeValue = (DfaTypeValue)dfaRight; + switch (relationType) { + case EQ: + case NE: + return !(dfaRelation.isEquality() && typeValue.isNotNull() && isNull(dfaVar)); + case IS_NOT: { + DfaVariableState newState = getVariableState(dfaVar).withNotInstanceofValue(typeValue); + if (newState != null) { + setVariableState(dfaVar, newState); + return true; + } + return !getVariableState(dfaVar).isNotNull() && applyRelation(dfaVar, myFactory.getConstFactory().getNull(), false); } - return true; + case IS: + if (applyRelation(dfaVar, myFactory.getConstFactory().getNull(), true)) { + DfaVariableState newState = getVariableState(dfaVar).withInstanceofValue(typeValue); + if (newState != null) { + setVariableState(dfaVar, newState); + return true; + } + } + return false; + default: } - - if (isNegated) { - DfaVariableState newState = getVariableState(dfaVar).withNotInstanceofValue((DfaTypeValue)dfaRight); - if (newState != null) { - setVariableState(dfaVar, newState); - return true; - } - return !getVariableState(dfaVar).isNotNull() && applyRelation(dfaVar, myFactory.getConstFactory().getNull(), false); - } - if (applyRelation(dfaVar, myFactory.getConstFactory().getNull(), true)) { - DfaVariableState newState = getVariableState(dfaVar).withInstanceofValue((DfaTypeValue)dfaRight); - if (newState != null) { - setVariableState(dfaVar, newState); - return true; - } - } - return false; } return true; } if (isEffectivelyNaN(dfaLeft) || isEffectivelyNaN(dfaRight)) { applyEquivalenceRelation(dfaRelation, dfaLeft, dfaRight); - return isNegated; + return relationType == RelationType.NE; } if (canBeNaN(dfaLeft) && canBeNaN(dfaRight)) { if (dfaLeft == dfaRight && dfaLeft instanceof DfaVariableValue && !(((DfaVariableValue)dfaLeft).getVariableType() instanceof PsiPrimitiveType)) { - return !isNegated; + return !dfaRelation.isNonEquality(); } applyEquivalenceRelation(dfaRelation, dfaLeft, dfaRight); @@ -899,12 +928,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } static boolean isNaN(final DfaValue dfa) { - if (dfa instanceof DfaConstValue) { - Object value = ((DfaConstValue)dfa).getValue(); - if (value instanceof Double && ((Double)value).isNaN()) return true; - if (value instanceof Float && ((Float)value).isNaN()) return true; - } - return false; + return dfa instanceof DfaConstValue && DfaUtil.isNaN(((DfaConstValue)dfa).getValue()); } private boolean applyRelation(@NotNull final DfaValue dfaLeft, @NotNull final DfaValue dfaRight, boolean isNegated) { @@ -1027,50 +1051,18 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } return LongRangeSet.fromType(var.getVariableType()); } - return range; - } - if (value instanceof DfaRangeValue) { - return ((DfaRangeValue)value).getValue(); - } - if (value instanceof DfaConstValue) { - return LongRangeSet.fromConstant(((DfaConstValue)value).getValue()); - } - return null; - } - - @Override - public DfaValue getStringLength(DfaValue value) { - if (value instanceof DfaVariableValue) { - DfaVariableValue variableValue = (DfaVariableValue)value; - DfaConstValue constValue = getConstantValue(variableValue); - if(constValue != null) { - value = constValue; - } else { - PsiType type = variableValue.getVariableType(); - if (type != null && type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { - PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(type); - if (psiClass != null) { - PsiMethod[] lengthMethods = psiClass.findMethodsByName("length", false); - if (lengthMethods.length == 1) { - return getFactory().getVarFactory().createVariableValue(lengthMethods[0], PsiType.INT, false, variableValue); - } + if (var.getPsiVariable() instanceof PsiMethod && MethodUtils.isStringLength((PsiMethod)var.getPsiVariable())) { + DfaVariableValue qualifier = var.getQualifier(); + if(qualifier != null) { + DfaConstValue constValue = getConstantValue(qualifier); + if (constValue != null && constValue.getValue() instanceof String) { + return LongRangeSet.point(((String)constValue.getValue()).length()); } } } + return range; } - if(value instanceof DfaConstValue) { - Object str = ((DfaConstValue)value).getValue(); - if(str instanceof String) { - return getFactory().getRangeFactory().create(LongRangeSet.point(((String)str).length())); - } - } - return DfaUnknownValue.getInstance(); - } - - @Nullable - private DfaRelationValue compareToNull(DfaValue dfaVar, boolean negated) { - DfaConstValue dfaNull = myFactory.getConstFactory().getNull(); - return myFactory.getRelationFactory().createRelation(dfaVar, dfaNull, JavaTokenType.EQEQ, negated); + return LongRangeSet.fromDfaValue(value); } void setVariableState(DfaVariableValue dfaVar, DfaVariableState state) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java index e37d308cecef..007e0b5638b0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -255,4 +255,10 @@ public class DfaUtil { return concatenation.getHead(); } } + + public static boolean isNaN(Object value) { + if (value instanceof Double && ((Double)value).isNaN()) return true; + if (value instanceof Float && ((Float)value).isNaN()) return true; + return false; + } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/HardcodedContracts.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/HardcodedContracts.java index 4d53a925a89d..2ee27d0239d8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/HardcodedContracts.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/HardcodedContracts.java @@ -15,65 +15,32 @@ */ package com.intellij.codeInspection.dataFlow; +import com.intellij.codeInspection.dataFlow.value.DfaOptionalValue; +import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType; import com.intellij.codeInspection.dataFlow.value.DfaValue; +import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.ThreeState; import com.intellij.util.containers.ContainerUtil; import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.TypeUtils; +import one.util.streamex.IntStreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import static com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint.*; -import static com.intellij.codeInspection.dataFlow.MethodContract.createConstraintArray; +import static com.intellij.codeInspection.dataFlow.StandardMethodContract.createConstraintArray; /** * @author peter */ public class HardcodedContracts { - static class OptionalPresenceContract extends MethodContract.QualifierBasedContract { - private final boolean myPresent; - - public OptionalPresenceContract(boolean mustPresent, ValueConstraint[] valueConstraints, ValueConstraint returnValue) { - super(valueConstraints, returnValue); - myPresent = mustPresent; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass() || !super.equals(o)) return false; - return myPresent == ((OptionalPresenceContract)o).myPresent; - } - - @Override - public int hashCode() { - return 31 * super.hashCode() + (myPresent ? 1 : 0); - } - - @Override - boolean applyContract(boolean matches, DfaValue qualifier, DfaMemoryState memoryState) { - boolean present = !matches ^ myPresent; - ThreeState state = memoryState.checkOptional(qualifier); - if(state == ThreeState.fromBoolean(!present)) return false; - if(state == ThreeState.UNSURE) { - memoryState.applyIsPresentCheck(present, qualifier); - } - return true; - } - - @Override - public String toString() { - return "[" + (myPresent ? "present" : "absent") + "] " + super.toString(); - } - } - public static List getHardcodedContracts(@NotNull PsiMethod method, @Nullable PsiMethodCallExpression call) { PsiClass owner = method.getContainingClass(); if (owner == null || @@ -89,7 +56,7 @@ public class HardcodedContracts { if ("java.lang.System".equals(className)) { if ("exit".equals(methodName)) { - return Collections.singletonList(new MethodContract(createConstraintArray(paramCount), THROW_EXCEPTION)); + return Collections.singletonList(new StandardMethodContract(createConstraintArray(paramCount), THROW_EXCEPTION)); } } else if ("com.google.common.base.Preconditions".equals(className)) { @@ -99,7 +66,7 @@ public class HardcodedContracts { if (("checkArgument".equals(methodName) || "checkState".equals(methodName)) && paramCount > 0) { MethodContract.ValueConstraint[] constraints = createConstraintArray(paramCount); constraints[0] = FALSE_VALUE; - return Collections.singletonList(new MethodContract(constraints, THROW_EXCEPTION)); + return Collections.singletonList(new StandardMethodContract(constraints, THROW_EXCEPTION)); } } else if ("java.util.Objects".equals(className)) { @@ -107,18 +74,35 @@ public class HardcodedContracts { return failIfNull(0, paramCount); } } + else if ("java.lang.String".equals(className)) { + if (("charAt".equals(methodName) || "codePointAt".equals(methodName)) && paramCount == 1) { + return Arrays.asList(new NonnegativeArgumentContract(1, 0), + new StringLengthContract(1, 0, RelationType.LT)); + } + else if (("substring".equals(methodName) || "subSequence".equals(methodName)) && paramCount <= 2) { + List contracts = new ArrayList<>(5); + contracts.add(new NonnegativeArgumentContract(paramCount, 0)); + contracts.add(new StringLengthContract(paramCount, 0, RelationType.LE)); + if (paramCount == 2) { + contracts.add(new NonnegativeArgumentContract(paramCount, 1)); + contracts.add(new StringLengthContract(paramCount, 1, RelationType.LE)); + contracts.add(new ArgumentRelationContract(paramCount, 0, RelationType.LE, 1)); + } + return contracts; + } + } else if ("org.apache.commons.lang.Validate".equals(className) || "org.apache.commons.lang3.Validate".equals(className) || "org.springframework.util.Assert".equals(className)) { if (("isTrue".equals(methodName) || "state".equals(methodName)) && paramCount > 0) { MethodContract.ValueConstraint[] constraints = createConstraintArray(paramCount); constraints[0] = FALSE_VALUE; - return Collections.singletonList(new MethodContract(constraints, THROW_EXCEPTION)); + return Collections.singletonList(new StandardMethodContract(constraints, THROW_EXCEPTION)); } if ("notNull".equals(methodName) && paramCount > 0) { MethodContract.ValueConstraint[] constraints = createConstraintArray(paramCount); constraints[0] = NULL_VALUE; - return Collections.singletonList(new MethodContract(constraints, THROW_EXCEPTION)); + return Collections.singletonList(new StandardMethodContract(constraints, THROW_EXCEPTION)); } } else if (isJunit(className) || isTestng(className) || @@ -127,20 +111,135 @@ public class HardcodedContracts { return handleTestFrameworks(paramCount, className, methodName, call); } else if (TypeUtils.isOptional(owner)) { - MethodContract.ValueConstraint[] constraints = createConstraintArray(paramCount); if (DfaOptionalSupport.isOptionalGetMethodName(methodName) || "orElseThrow".equals(methodName)) { - return Arrays.asList(new OptionalPresenceContract(false, constraints, THROW_EXCEPTION), - new OptionalPresenceContract(true, constraints, NOT_NULL_VALUE)); + return Arrays.asList(new OptionalPresenceContract(false, THROW_EXCEPTION), + new OptionalPresenceContract(true, NOT_NULL_VALUE)); } else if ("isPresent".equals(methodName)) { - return Arrays.asList(new OptionalPresenceContract(false, constraints, FALSE_VALUE), - new OptionalPresenceContract(true, constraints, TRUE_VALUE)); + return Arrays.asList(new OptionalPresenceContract(false, FALSE_VALUE), + new OptionalPresenceContract(true, TRUE_VALUE)); } } return Collections.emptyList(); } + static class OptionalPresenceContract extends MethodContract { + private final boolean myPresent; + private final ValueConstraint myReturnValue; + + public OptionalPresenceContract(boolean mustPresent, ValueConstraint returnValue) { + myReturnValue = returnValue; + myPresent = mustPresent; + } + + @Override + List getConditions(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) { + DfaOptionalValue optional = factory.getOptionalFactory().getOptional(myPresent); + return Collections.singletonList(factory.createCondition(qualifier, RelationType.IS, optional)); + } + + @Override + String getArgumentsPresentation() { + return "[" + (myPresent ? "present" : "absent") + "]"; + } + + @Override + public ValueConstraint getReturnValue() { + return myReturnValue; + } + } + + static abstract class ArgumentRangeContract extends MethodContract { + final int myParamCount; + final int myIndex; + final RelationType myRelationType; + + ArgumentRangeContract(int paramCount, int index, RelationType type) { + myParamCount = paramCount; + myIndex = index; + myRelationType = type; + } + + @Override + List getConditions(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) { + DfaValue left = arguments[myIndex]; + DfaValue right = getBound(factory, qualifier, arguments); + return Collections.singletonList(factory.createCondition(left, myRelationType.getNegated(), right)); + } + + @NotNull + abstract DfaValue getBound(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments); + + abstract String getBoundRepresentation(); + + @Override + String getArgumentsPresentation() { + return IntStreamEx.range(myParamCount) + .mapToObj(idx -> idx == myIndex ? myRelationType.getNegated() + getBoundRepresentation() : "_") + .joining(", "); + } + + @Override + public ValueConstraint getReturnValue() { + return THROW_EXCEPTION; + } + } + + static class NonnegativeArgumentContract extends ArgumentRangeContract { + public NonnegativeArgumentContract(int paramCount, int nonNegativeArgumentIndex) { + super(paramCount, nonNegativeArgumentIndex, RelationType.GE); + } + + @NotNull + @Override + DfaValue getBound(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) { + return factory.getConstFactory().createFromValue(0, PsiType.INT, null); + } + + @Override + String getBoundRepresentation() { + return "0"; + } + } + + static class ArgumentRelationContract extends ArgumentRangeContract { + private final int myIndex; + + public ArgumentRelationContract(int paramCount, int leftIndex, RelationType relationType, int rightIndex) { + super(paramCount, leftIndex, relationType); + myIndex = rightIndex; + } + + @NotNull + @Override + DfaValue getBound(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) { + return arguments[myIndex]; + } + + @Override + String getBoundRepresentation() { + return "arg#" + myIndex; + } + } + + static class StringLengthContract extends ArgumentRangeContract { + StringLengthContract(int paramCount, int index, RelationType type) { + super(paramCount, index, type); + } + + @NotNull + @Override + DfaValue getBound(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) { + return factory.createStringLength(qualifier); + } + + @Override + String getBoundRepresentation() { + return "this.length()"; + } + } + private static boolean isJunit(String className) { return className.startsWith("junit.framework.") || className.startsWith("org.junit."); } @@ -182,7 +281,7 @@ public class HardcodedContracts { boolean testng = isTestng(className); if ("fail".equals(methodName)) { - return Collections.singletonList(new MethodContract(createConstraintArray(paramCount), THROW_EXCEPTION)); + return Collections.singletonList(new StandardMethodContract(createConstraintArray(paramCount), THROW_EXCEPTION)); } if (paramCount == 0) return Collections.emptyList(); @@ -191,15 +290,15 @@ public class HardcodedContracts { MethodContract.ValueConstraint[] constraints = createConstraintArray(paramCount); if ("assertTrue".equals(methodName) || "assumeTrue".equals(methodName)) { constraints[checkedParam] = FALSE_VALUE; - return Collections.singletonList(new MethodContract(constraints, THROW_EXCEPTION)); + return Collections.singletonList(new StandardMethodContract(constraints, THROW_EXCEPTION)); } if ("assertFalse".equals(methodName) || "assumeFalse".equals(methodName)) { constraints[checkedParam] = TRUE_VALUE; - return Collections.singletonList(new MethodContract(constraints, THROW_EXCEPTION)); + return Collections.singletonList(new StandardMethodContract(constraints, THROW_EXCEPTION)); } if ("assertNull".equals(methodName)) { constraints[checkedParam] = NOT_NULL_VALUE; - return Collections.singletonList(new MethodContract(constraints, THROW_EXCEPTION)); + return Collections.singletonList(new StandardMethodContract(constraints, THROW_EXCEPTION)); } if ("assertNotNull".equals(methodName) || "assumeNotNull".equals(methodName)) { return failIfNull(checkedParam, paramCount); @@ -239,7 +338,7 @@ public class HardcodedContracts { private static List failIfNull(int argIndex, int argCount) { MethodContract.ValueConstraint[] constraints = createConstraintArray(argCount); constraints[argIndex] = NULL_VALUE; - return Collections.singletonList(new MethodContract(constraints, THROW_EXCEPTION)); + return Collections.singletonList(new StandardMethodContract(constraints, THROW_EXCEPTION)); } public static boolean isHardcodedPure(PsiMethod method) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InferenceFromSourceUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InferenceFromSourceUtil.java index b76aa964ec22..076814d3204a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InferenceFromSourceUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InferenceFromSourceUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -90,7 +90,7 @@ public class InferenceFromSourceUtil { static boolean suppressNullable(PsiMethod method) { if (method.getParameterList().getParametersCount() == 0) return false; - for (MethodContract contract : ControlFlowAnalyzer.getMethodContracts(method)) { + for (StandardMethodContract contract : ControlFlowAnalyzer.getMethodContracts(method)) { if (contract.returnValue == MethodContract.ValueConstraint.NULL_VALUE) { return true; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodContract.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodContract.java index b61aa1015216..aa76b93e8464 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodContract.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodContract.java @@ -16,71 +16,45 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInspection.dataFlow.value.DfaConstValue; +import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType; import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.List; -import java.util.function.Predicate; +import java.util.Objects; /** - * @author peter + * A method contract which states that method will have a concrete return value + * if arguments fulfill some constraint. + * + * @author Tagir Valeev */ -public class MethodContract { - public final ValueConstraint[] arguments; - public final ValueConstraint returnValue; +public abstract class MethodContract { + // package private to avoid uncontrolled implementations + MethodContract() { - public MethodContract(@NotNull ValueConstraint[] arguments, @NotNull ValueConstraint returnValue) { - this.arguments = arguments; - this.returnValue = returnValue; } - @NotNull - static ValueConstraint[] createConstraintArray(int paramCount) { - ValueConstraint[] args = new ValueConstraint[paramCount]; - for (int i = 0; i < args.length; i++) { - args[i] = ValueConstraint.ANY_VALUE; - } - return args; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || o.getClass() != getClass()) return false; - - MethodContract contract = (MethodContract)o; - - if (!Arrays.equals(arguments, contract.arguments)) return false; - if (returnValue != contract.returnValue) return false; - - return true; - } - - @Override - public int hashCode() { - int result = 0; - for (ValueConstraint argument : arguments) { - result = 31 * result + argument.ordinal(); - } - result = 31 * result + returnValue.ordinal(); - return result; - } - - @Override - public String toString() { - return StringUtil.join(arguments, constraint -> constraint.toString(), ", ") + " -> " + returnValue; - } + /** + * @return a value the method will return if the contract conditions fulfill + */ + public abstract ValueConstraint getReturnValue(); /** * @return true if this contract result does not depend on arguments */ boolean isTrivial() { - return Arrays.stream(this.arguments).allMatch(Predicate.isEqual(ValueConstraint.ANY_VALUE)); + return false; + } + + abstract String getArgumentsPresentation(); + + abstract List getConditions(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments); + + @Override + public String toString() { + return getArgumentsPresentation() + " -> " + getReturnValue(); } public enum ValueConstraint { @@ -102,62 +76,25 @@ public class MethodContract { return this == NOT_NULL_VALUE || this == FALSE_VALUE; } + /** + * Returns a condition value which should be applied to memory state to satisfy this constraint + * + * @param factory factory to create new values + * @param argValue argument value to test + * @return a condition + */ + public DfaValue getCondition(DfaValueFactory factory, DfaValue argValue) { + if (this == THROW_EXCEPTION || this == ANY_VALUE) { + return factory.getBoolean(true); + } + DfaConstValue expectedValue = Objects.requireNonNull(getComparisonValue(factory)); + + return factory.createCondition(argValue, RelationType.equivalence(!shouldUseNonEqComparison()), expectedValue); + } + @Override public String toString() { return myPresentableName; } } - - public static List parseContract(String text) throws ParseException { - List result = ContainerUtil.newArrayList(); - for (String clause : StringUtil.replace(text, " ", "").split(";")) { - String arrow = "->"; - int arrowIndex = clause.indexOf(arrow); - if (arrowIndex < 0) { - throw new ParseException("A contract clause must be in form arg1, ..., argN -> return-value"); - } - - String beforeArrow = clause.substring(0, arrowIndex); - ValueConstraint[] args; - if (StringUtil.isNotEmpty(beforeArrow)) { - String[] argStrings = beforeArrow.split(","); - args = new ValueConstraint[argStrings.length]; - for (int i = 0; i < args.length; i++) { - args[i] = parseConstraint(argStrings[i]); - } - } else { - args = new ValueConstraint[0]; - } - result.add(new MethodContract(args, parseConstraint(clause.substring(arrowIndex + arrow.length())))); - } - return result; - } - - private static ValueConstraint parseConstraint(String name) throws ParseException { - if (StringUtil.isEmpty(name)) throw new ParseException("Constraint should not be empty"); - for (ValueConstraint constraint : ValueConstraint.values()) { - if (constraint.toString().equals(name)) return constraint; - } - throw new ParseException("Constraint should be one of: null, !null, true, false, fail, _. Found: " + name); - } - - public static class ParseException extends Exception { - private ParseException(String message) { - super(message); - } - } - - abstract static class QualifierBasedContract extends MethodContract { - public QualifierBasedContract(@NotNull ValueConstraint[] arguments, - @NotNull ValueConstraint returnValue) { - super(arguments, returnValue); - } - - @Override - boolean isTrivial() { - return false; - } - - abstract boolean applyContract(boolean matches, DfaValue qualifier, DfaMemoryState memoryState); - } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodDataExternalizer.kt b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodDataExternalizer.kt index 039bf87a9236..eca41a668c8a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodDataExternalizer.kt +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodDataExternalizer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -90,7 +90,7 @@ internal object MethodDataExternalizer : DataExternalizer> } private fun readContract(input: DataInput): PreContract = when (input.readByte().toInt()) { 0 -> DelegationContract(readRange(input), input.readBoolean()) - 1 -> KnownContract(MethodContract(readContractArguments(input).toTypedArray(), readValueConstraint(input))) + 1 -> KnownContract(StandardMethodContract(readContractArguments(input).toTypedArray(), readValueConstraint(input))) 2 -> MethodCallContract(readRange(input), readSeq(input) { readContractArguments(input) }) 3 -> NegatingContract(readContract(input)) else -> SideEffectFilter(readRanges(input), readSeq(input) { readContract(input) }) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index ed0a7cfefab2..9fafc37a9593 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -16,10 +16,10 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.codeInspection.dataFlow.MethodContract.QualifierBasedContract; import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet; import com.intellij.codeInspection.dataFlow.value.*; +import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; @@ -33,16 +33,14 @@ import com.intellij.util.containers.FactoryMap; import com.intellij.util.containers.MultiMap; import com.siyeh.ig.callMatcher.CallMapper; import com.siyeh.ig.callMatcher.CallMatcher; -import com.siyeh.ig.psiutils.ComparisonUtils; import com.siyeh.ig.psiutils.TypeUtils; import gnu.trove.THashSet; +import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; -import static com.intellij.psi.JavaTokenType.*; - /** * @author peter */ @@ -84,6 +82,12 @@ public class StandardInstructionVisitor extends InstructionVisitor { DfaValue dfaSource = memState.pop(); DfaValue dfaDest = memState.pop(); + if (instruction.getAssignedValue() != null) { + // It's possible that dfaDest on the stack is cleared to DfaTypeValue due to variable flush + // (e.g. during StateMerger#mergeByFacts), so we try to restore the original destination. + dfaDest = instruction.getAssignedValue(); + } + if (dfaDest instanceof DfaVariableValue) { DfaVariableValue var = (DfaVariableValue) dfaDest; @@ -180,7 +184,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { DfaValue dfaExpr = factory.createValue(instruction.getCasted()); if (dfaExpr != null) { DfaTypeValue dfaType = (DfaTypeValue)factory.createTypeValue(instruction.getCastTo(), Nullness.UNKNOWN); - DfaRelationValue dfaInstanceof = factory.getRelationFactory().createRelation(dfaExpr, dfaType, INSTANCEOF_KEYWORD, false); + DfaRelationValue dfaInstanceof = factory.getRelationFactory().createRelation(dfaExpr, RelationType.IS, dfaType); if (dfaInstanceof != null && !memState.applyInstanceofOrNull(dfaInstanceof)) { onInstructionProducesCCE(instruction); } @@ -265,35 +269,34 @@ public class StandardInstructionVisitor extends InstructionVisitor { DfaValue[] argValues = popCallArguments(instruction, runner, memState, false); DfaValue qualifier = popQualifier(instruction, runner, memState); DfaValue result = null; + DfaValueFactory factory = runner.getFactory(); switch (methodName) { case "of": case "ofNullable": case "fromNullable": if ("of".equals(methodName) || (argValues != null && argValues.length == 1 && memState.isNotNull(argValues[0]))) { - result = runner.getFactory().getOptionalFactory().getOptional(true); + result = factory.getOptionalFactory().getOptional(true); } break; case "empty": case "absent": - result = runner.getFactory().getOptionalFactory().getOptional(false); + result = factory.getOptionalFactory().getOptional(false); break; case "orElse": if (argValues != null && argValues.length == 1) { - switch (memState.checkOptional(qualifier)) { - case YES: - result = runner.getFactory().createTypeValue(instruction.getResultType(), Nullness.NOT_NULL); - break; - case NO: - result = argValues[0]; - break; - case UNSURE: - DfaMemoryState falseState = memState.createCopy(); - memState.push(runner.getFactory().createTypeValue(instruction.getResultType(), Nullness.NOT_NULL)); - memState.applyIsPresentCheck(true, qualifier); - falseState.push(argValues[0]); - falseState.applyIsPresentCheck(false, qualifier); - return Arrays.asList(memState, falseState); + DfaMemoryState falseState = memState.createCopy(); + DfaOptionalValue optional = factory.getOptionalFactory().getOptional(true); + DfaValue relation = factory.createCondition(qualifier, RelationType.IS, optional); + List states = new ArrayList<>(2); + if (memState.applyCondition(relation)) { + memState.push(factory.createTypeValue(instruction.getResultType(), Nullness.NOT_NULL)); + states.add(memState); } + if (falseState.applyCondition(relation.createNegated())) { + falseState.push(argValues[0]); + states.add(falseState); + } + return states; } break; case "filter": @@ -302,14 +305,17 @@ public class StandardInstructionVisitor extends InstructionVisitor { case "map": case "or": case "orElseGet": - case "transform": + case "transform": { + DfaOptionalValue optional = factory.getOptionalFactory().getOptional(!methodName.startsWith("or")); + DfaValue relation = factory.createCondition(qualifier, RelationType.IS, optional); for (DfaMemoryState closure : closures) { - closure.applyIsPresentCheck(!methodName.startsWith("or"), qualifier); + closure.applyCondition(relation); } break; + } default: } - memState.push(result == null ? getMethodResultValue(instruction, qualifier, runner.getFactory()) : result); + memState.push(result == null ? getMethodResultValue(instruction, qualifier, factory) : result); return Collections.singletonList(memState); } @@ -377,69 +383,41 @@ public class StandardInstructionVisitor extends InstructionVisitor { MethodCallInstruction instruction, DfaValueFactory factory, Set finalStates) { - DfaConstValue.Factory constFactory = factory.getConstFactory(); + List conditions = contract.getConditions(factory, qualifier, argValues); + if (StreamEx.of(conditions).allMatch(factory.getConstFactory().getTrue()::equals)) { + for (DfaMemoryState state : states) { + state.push(getDfaContractReturnValue(contract, instruction, factory)); + finalStates.add(state); + } + return new LinkedHashSet<>(); + } + if (StreamEx.of(conditions).has(factory.getConstFactory().getFalse())) { + return states; + } + LinkedHashSet falseStates = ContainerUtil.newLinkedHashSet(); - for (int i = 0; i < argValues.length; i++) { - DfaValue argValue = argValues[i]; - MethodContract.ValueConstraint constraint = contract.arguments[i]; - DfaConstValue expectedValue = constraint.getComparisonValue(factory); - if (expectedValue == null) continue; - - boolean nullContract = expectedValue == constFactory.getNull(); - boolean invertCondition = constraint.shouldUseNonEqComparison(); - DfaValue condition = factory.getRelationFactory().createRelation(argValue, expectedValue, EQEQ, invertCondition); - if (condition == null) { - if (!(argValue instanceof DfaConstValue)) { - for (DfaMemoryState state : states) { - DfaMemoryState falseCopy = state.createCopy(); - if (nullContract) { - (invertCondition ? falseCopy : state).markEphemeral(); - } - falseStates.add(falseCopy); - } - continue; - } - condition = constFactory.createFromValue((argValue == expectedValue) != invertCondition, PsiType.BOOLEAN, null); - } - - LinkedHashSet nextStates = ContainerUtil.newLinkedHashSet(); - for (DfaMemoryState state : states) { - boolean unknownVsNull = nullContract && - argValue instanceof DfaVariableValue && - ((DfaMemoryStateImpl)state).getVariableState((DfaVariableValue)argValue).getNullability() == Nullness.UNKNOWN; - DfaMemoryState falseCopy = state.createCopy(); - if (state.applyCondition(condition)) { - if (unknownVsNull && !invertCondition) { - state.markEphemeral(); - } - nextStates.add(state); - } - if (falseCopy.applyCondition(condition.createNegated())) { - if (unknownVsNull && invertCondition) { - falseCopy.markEphemeral(); - } - falseStates.add(falseCopy); - } - } - states = nextStates; - } - - if (contract instanceof QualifierBasedContract) { - LinkedHashSet nextStates = ContainerUtil.newLinkedHashSet(); - QualifierBasedContract qualifierBasedContract = (QualifierBasedContract)contract; - for (DfaMemoryState state : states) { - DfaMemoryState falseCopy = state.createCopy(); - if (qualifierBasedContract.applyContract(true, qualifier, state)) { - nextStates.add(state); - } - if (qualifierBasedContract.applyContract(false, qualifier, falseCopy)) { - falseStates.add(falseCopy); - } - } - states = nextStates; - } + LinkedHashSet trueStates = ContainerUtil.newLinkedHashSet(); for (DfaMemoryState state : states) { + for (DfaValue condition : conditions) { + if (condition == null) { + condition = DfaUnknownValue.getInstance(); + } + DfaMemoryState falseState = state.createCopy(); + if (falseState.applyContractCondition(condition.createNegated())) { + falseStates.add(falseState); + } + if (!state.applyContractCondition(condition)) { + state = null; + break; + } + } + if(state != null) { + trueStates.add(state); + } + } + + for (DfaMemoryState state : trueStates) { state.push(getDfaContractReturnValue(contract, instruction, factory)); finalStates.add(state); } @@ -450,7 +428,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { private DfaValue getDfaContractReturnValue(MethodContract contract, MethodCallInstruction instruction, DfaValueFactory factory) { - switch (contract.returnValue) { + switch (contract.getReturnValue()) { case NULL_VALUE: return factory.getConstFactory().getNull(); case NOT_NULL_VALUE: return factory.createTypeValue(instruction.getResultType(), Nullness.NOT_NULL); case TRUE_VALUE: return factory.getConstFactory().getTrue(); @@ -529,7 +507,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { if (notNullable && problem != NullabilityProblem.passingNullableArgumentToNonAnnotatedParameter) { DfaValueFactory factory = ((DfaMemoryStateImpl)state).getFactory(); - state.applyCondition(factory.getRelationFactory().createRelation(value, factory.getConstFactory().getNull(), NE, false)); + state.applyCondition(factory.createCondition(value, RelationType.NE, factory.getConstFactory().getNull())); } return notNullable; } @@ -542,27 +520,25 @@ public class StandardInstructionVisitor extends InstructionVisitor { DfaValue dfaLeft = memState.pop(); final IElementType opSign = instruction.getOperationSign(); - if (ComparisonUtils.isComparisonOperation(opSign) || opSign == INSTANCEOF_KEYWORD) { - DfaInstructionState[] states = handleConstantComparison(instruction, runner, memState, dfaRight, dfaLeft, opSign); + RelationType relationType = RelationType.fromElementType(opSign); + if (relationType != null) { + DfaInstructionState[] states = handleConstantComparison(instruction, runner, memState, dfaRight, dfaLeft, relationType); if (states == null) { - states = handleRangeComparison(instruction, runner, memState, dfaRight, dfaLeft, opSign); - } - if (states == null) { - states = handleRelationBinop(instruction, runner, memState, dfaRight, dfaLeft); + states = handleRelationBinop(instruction, runner, memState, dfaRight, dfaLeft, relationType); } if (states != null) { return states; } } DfaValue result = null; - if (AND == opSign) { + if (JavaTokenType.AND == opSign) { LongRangeSet left = memState.getRange(dfaLeft); LongRangeSet right = memState.getRange(dfaRight); if(left != null && right != null) { result = runner.getFactory().getRangeFactory().create(left.bitwiseAnd(right)); } } - else if (PLUS == opSign) { + else if (JavaTokenType.PLUS == opSign) { result = instruction.getNonNullStringValue(runner.getFactory()); } else { @@ -582,20 +558,20 @@ public class StandardInstructionVisitor extends InstructionVisitor { private DfaInstructionState[] handleRelationBinop(BinopInstruction instruction, DataFlowRunner runner, DfaMemoryState memState, - DfaValue dfaRight, DfaValue dfaLeft) { + DfaValue dfaRight, + DfaValue dfaLeft, + RelationType relationType) { DfaValueFactory factory = runner.getFactory(); final Instruction next = runner.getInstruction(instruction.getIndex() + 1); - DfaRelationValue dfaRelation = factory.getRelationFactory().createRelation(dfaLeft, dfaRight, instruction.getOperationSign(), false); - if (dfaRelation == null) { - return null; - } + DfaValue condition = factory.createCondition(dfaLeft, relationType, dfaRight); + if (condition instanceof DfaUnknownValue) return null; myCanBeNullInInstanceof.add(instruction); - ArrayList states = new ArrayList<>(); + ArrayList states = new ArrayList<>(2); final DfaMemoryState trueCopy = memState.createCopy(); - if (trueCopy.applyCondition(dfaRelation)) { + if (trueCopy.applyCondition(condition)) { trueCopy.push(factory.getConstFactory().getTrue()); instruction.setTrueReachable(); states.add(new DfaInstructionState(next, trueCopy)); @@ -603,7 +579,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { //noinspection UnnecessaryLocalVariable DfaMemoryState falseCopy = memState; - if (falseCopy.applyCondition(dfaRelation.createNegated())) { + if (falseCopy.applyCondition(condition.createNegated())) { falseCopy.push(factory.getConstFactory().getFalse()); instruction.setFalseReachable(); states.add(new DfaInstructionState(next, falseCopy)); @@ -632,45 +608,24 @@ public class StandardInstructionVisitor extends InstructionVisitor { myUsefulInstanceofs.add(instruction); } - @Nullable - private static DfaInstructionState[] handleRangeComparison(BinopInstruction instruction, - DataFlowRunner runner, - DfaMemoryState state, - DfaValue right, - DfaValue left, IElementType sign) { - LongRangeSet leftRange = state.getRange(left); - if (leftRange == null) return null; - LongRangeSet rightRange = state.getRange(right); - if (rightRange == null) return null; - LongRangeSet constraint = rightRange.fromRelation(sign); - if (constraint != null && !constraint.intersects(leftRange)) { - return alwaysFalse(instruction, runner, state); - } - LongRangeSet revConstraint = rightRange.fromRelation(ComparisonUtils.getNegatedComparisonTokenType(sign)); - if (revConstraint != null && !revConstraint.intersects(leftRange)) { - return alwaysTrue(instruction, runner, state); - } - return null; - } - @Nullable private static DfaInstructionState[] handleConstantComparison(BinopInstruction instruction, DataFlowRunner runner, DfaMemoryState memState, DfaValue dfaRight, - DfaValue dfaLeft, IElementType opSign) { + DfaValue dfaLeft, RelationType relationType) { if (dfaLeft instanceof DfaVariableValue && dfaRight instanceof DfaVariableValue) { Number leftValue = getKnownNumberValue(memState, (DfaVariableValue)dfaLeft); Number rightValue = getKnownNumberValue(memState, (DfaVariableValue)dfaRight); if (leftValue != null && rightValue != null) { - return checkComparisonWithKnownValue(instruction, runner, memState, opSign, leftValue, rightValue); + return checkComparisonWithKnownValue(instruction, runner, memState, relationType, leftValue, rightValue); } } if (dfaRight instanceof DfaConstValue && dfaLeft instanceof DfaVariableValue) { Object value = ((DfaConstValue)dfaRight).getValue(); if (value instanceof Number) { - DfaInstructionState[] result = checkComparingWithConstant(instruction, runner, memState, (DfaVariableValue)dfaLeft, opSign, + DfaInstructionState[] result = checkComparingWithConstant(instruction, runner, memState, (DfaVariableValue)dfaLeft, relationType, (Number)value); if (result != null) { return result; @@ -678,17 +633,17 @@ public class StandardInstructionVisitor extends InstructionVisitor { } } if (dfaRight instanceof DfaVariableValue && dfaLeft instanceof DfaConstValue) { - return handleConstantComparison(instruction, runner, memState, dfaLeft, dfaRight, DfaRelationValue.getSymmetricOperation(opSign)); + return handleConstantComparison(instruction, runner, memState, dfaLeft, dfaRight, relationType.getFlipped()); } - if (EQEQ != opSign && NE != opSign) { + if (relationType != RelationType.EQ && relationType != RelationType.NE) { return null; } if (dfaLeft instanceof DfaConstValue && dfaRight instanceof DfaConstValue || dfaLeft == runner.getFactory().getConstFactory().getContractFail() || dfaRight == runner.getFactory().getConstFactory().getContractFail()) { - boolean negated = (NE == opSign) ^ (DfaMemoryStateImpl.isNaN(dfaLeft) || DfaMemoryStateImpl.isNaN(dfaRight)); + boolean negated = (relationType == RelationType.NE) ^ (DfaMemoryStateImpl.isNaN(dfaLeft) || DfaMemoryStateImpl.isNaN(dfaRight)); if (dfaLeft == dfaRight ^ negated) { return alwaysTrue(instruction, runner, memState); } @@ -703,7 +658,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { DataFlowRunner runner, DfaMemoryState memState, DfaVariableValue var, - IElementType opSign, Number comparedWith) { + RelationType opSign, Number comparedWith) { Number knownValue = getKnownNumberValue(memState, var); if (knownValue != null) { return checkComparisonWithKnownValue(instruction, runner, memState, opSign, knownValue, comparedWith); @@ -720,26 +675,27 @@ public class StandardInstructionVisitor extends InstructionVisitor { private static DfaInstructionState[] checkComparisonWithKnownValue(BinopInstruction instruction, DataFlowRunner runner, DfaMemoryState memState, - IElementType opSign, + RelationType opSign, Number leftValue, Number rightValue) { int cmp = compare(leftValue, rightValue); Boolean result = null; + boolean hasNaN = DfaUtil.isNaN(leftValue) || DfaUtil.isNaN(rightValue); if (cmp < 0 || cmp > 0) { - if(opSign == EQEQ) result = false; - else if (opSign == NE) result = true; + if(opSign == RelationType.EQ) result = false; + else if (opSign == RelationType.NE) result = true; } - if (opSign == LT) { - result = cmp < 0; + if (opSign == RelationType.LT) { + result = !hasNaN && cmp < 0; } - else if (opSign == GT) { - result = cmp > 0; + else if (opSign == RelationType.GT) { + result = !hasNaN && cmp > 0; } - else if (opSign == LE) { - result = cmp <= 0; + else if (opSign == RelationType.LE) { + result = !hasNaN && cmp <= 0; } - else if (opSign == GE) { - result = cmp >= 0; + else if (opSign == RelationType.GE) { + result = !hasNaN && cmp >= 0; } if (result == null) { return null; @@ -783,5 +739,4 @@ public class StandardInstructionVisitor extends InstructionVisitor { } return false; } - } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardMethodContract.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardMethodContract.java new file mode 100644 index 000000000000..739db41cca17 --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardMethodContract.java @@ -0,0 +1,134 @@ +/* + * Copyright 2000-2017 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.codeInspection.dataFlow; + +import com.intellij.codeInspection.dataFlow.value.DfaValue; +import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import one.util.streamex.StreamEx; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +/** + * A method contract which is described by {@link MethodContract.ValueConstraint} constraints on arguments. + * Such contract can be created from {@link org.jetbrains.annotations.Contract} annotation. + * + * @author peter + */ +public final class StandardMethodContract extends MethodContract { + public final ValueConstraint[] arguments; + public final ValueConstraint returnValue; + + public StandardMethodContract(@NotNull ValueConstraint[] arguments, @NotNull ValueConstraint returnValue) { + this.arguments = arguments; + this.returnValue = returnValue; + } + + @Override + public ValueConstraint getReturnValue() { + return returnValue; + } + + @NotNull + static ValueConstraint[] createConstraintArray(int paramCount) { + ValueConstraint[] args = new ValueConstraint[paramCount]; + for (int i = 0; i < args.length; i++) { + args[i] = ValueConstraint.ANY_VALUE; + } + return args; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || o.getClass() != getClass()) return false; + + StandardMethodContract contract = (StandardMethodContract)o; + + if (!Arrays.equals(arguments, contract.arguments)) return false; + if (returnValue != contract.returnValue) return false; + + return true; + } + + @Override + public int hashCode() { + int result = 0; + for (ValueConstraint argument : arguments) { + result = 31 * result + argument.ordinal(); + } + result = 31 * result + returnValue.ordinal(); + return result; + } + + boolean isTrivial() { + return Arrays.stream(this.arguments).allMatch(Predicate.isEqual(ValueConstraint.ANY_VALUE)); + } + + @Override + String getArgumentsPresentation() { + return StringUtil.join(arguments, constraint -> constraint.toString(), ", "); + } + + @Override + List getConditions(DfaValueFactory factory, DfaValue qualifier, DfaValue[] argValues) { + return StreamEx.zip(arguments, argValues, (constraint, value) -> constraint.getCondition(factory, value)) + .without(factory.getConstFactory().getTrue()).toList(); + } + + public static List parseContract(String text) throws ParseException { + List result = ContainerUtil.newArrayList(); + for (String clause : StringUtil.replace(text, " ", "").split(";")) { + String arrow = "->"; + int arrowIndex = clause.indexOf(arrow); + if (arrowIndex < 0) { + throw new ParseException("A contract clause must be in form arg1, ..., argN -> return-value"); + } + + String beforeArrow = clause.substring(0, arrowIndex); + ValueConstraint[] args; + if (StringUtil.isNotEmpty(beforeArrow)) { + String[] argStrings = beforeArrow.split(","); + args = new ValueConstraint[argStrings.length]; + for (int i = 0; i < args.length; i++) { + args[i] = parseConstraint(argStrings[i]); + } + } else { + args = new ValueConstraint[0]; + } + result.add(new StandardMethodContract(args, parseConstraint(clause.substring(arrowIndex + arrow.length())))); + } + return result; + } + + private static ValueConstraint parseConstraint(String name) throws ParseException { + if (StringUtil.isEmpty(name)) throw new ParseException("Constraint should not be empty"); + for (ValueConstraint constraint : ValueConstraint.values()) { + if (constraint.toString().equals(name)) return constraint; + } + throw new ParseException("Constraint should be one of: null, !null, true, false, fail, _. Found: " + name); + } + + public static class ParseException extends Exception { + private ParseException(String message) { + super(message); + } + } +} diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java index 6a08a151497c..6df7b7a89b33 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java @@ -17,9 +17,9 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet; import com.intellij.codeInspection.dataFlow.value.*; +import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.UnorderedPair; -import com.intellij.psi.JavaTokenType; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; @@ -119,7 +119,7 @@ class StateMerger { if (inequalitiesToRestore != null) { DfaRelationValue.Factory relationFactory = state.getFactory().getRelationFactory(); for (DfaConstValue toRestore : inequalitiesToRestore) { - state.applyCondition(relationFactory.createRelation(removedFact.myVar, toRestore, JavaTokenType.EQEQ, true)); + state.applyCondition(relationFactory.createRelation(removedFact.myVar, RelationType.NE, toRestore)); } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java index 295b53832ce8..e4b6b420622e 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -71,9 +71,9 @@ public class MethodCallInstruction extends Instruction { myArgRequiredNullability = Collections.emptyMap(); } - public MethodCallInstruction(@NotNull PsiCall call, @Nullable DfaValue precalculatedReturnValue, List contracts) { + public MethodCallInstruction(@NotNull PsiCall call, @Nullable DfaValue precalculatedReturnValue, List contracts) { myContext = call; - myContracts = contracts; + myContracts = Collections.unmodifiableList(contracts); myMethodType = MethodType.REGULAR_METHOD_CALL; myCall = call; final PsiExpressionList argList = call.getArgumentList(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/preContracts.kt b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/preContracts.kt index 2c3c7901f0c5..3504ff1b9cf8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/preContracts.kt +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/preContracts.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -27,18 +27,18 @@ import com.siyeh.ig.psiutils.SideEffectChecker * @author peter */ interface PreContract { - fun toContracts(method: PsiMethod, body: () -> PsiCodeBlock): List + fun toContracts(method: PsiMethod, body: () -> PsiCodeBlock): List fun negate(): PreContract? = NegatingContract(this) } -internal data class KnownContract(val contract: MethodContract) : PreContract { +internal data class KnownContract(val contract: StandardMethodContract) : PreContract { override fun toContracts(method: PsiMethod, body: () -> PsiCodeBlock) = listOf(contract) override fun negate() = negateContract(contract)?.let(::KnownContract) } internal data class DelegationContract(internal val expression: ExpressionRange, internal val negated: Boolean) : PreContract { - override fun toContracts(method: PsiMethod, body: () -> PsiCodeBlock): List { + override fun toContracts(method: PsiMethod, body: () -> PsiCodeBlock): List { val call = expression.restoreExpression(body()) as PsiMethodCallExpression? ?: return emptyList() val result = call.resolveMethodGenerics() @@ -52,7 +52,7 @@ internal data class DelegationContract(internal val expression: ExpressionRange, convertDelegatedMethodContract(method, parameters, arguments, varArgCall, dc) } if (NullableNotNullManager.isNotNull(targetMethod)) { - return fromDelegate.map { returnNotNull(it) } + listOf(MethodContract(emptyConstraints(method), NOT_NULL_VALUE)) + return fromDelegate.map { returnNotNull(it) } + listOf(StandardMethodContract(emptyConstraints(method), NOT_NULL_VALUE)) } return fromDelegate } @@ -61,7 +61,7 @@ internal data class DelegationContract(internal val expression: ExpressionRange, targetParameters: Array, callArguments: Array, varArgCall: Boolean, - targetContract: MethodContract): MethodContract? { + targetContract: StandardMethodContract): StandardMethodContract? { var answer: Array? = emptyConstraints(callerMethod) for (i in targetContract.arguments.indices) { if (i >= callArguments.size) return null @@ -85,12 +85,13 @@ internal data class DelegationContract(internal val expression: ExpressionRange, } } val returnValue = if (negated) negateConstraint(targetContract.returnValue) else targetContract.returnValue - return answer?.let { MethodContract(it, returnValue) } + return answer?.let { StandardMethodContract(it, returnValue) } } - private fun emptyConstraints(method: PsiMethod) = MethodContract.createConstraintArray(method.parameterList.parametersCount) + private fun emptyConstraints(method: PsiMethod) = StandardMethodContract.createConstraintArray(method.parameterList.parametersCount) - private fun returnNotNull(mc: MethodContract) = if (mc.returnValue == THROW_EXCEPTION) mc else MethodContract(mc.arguments, NOT_NULL_VALUE) + private fun returnNotNull(mc: StandardMethodContract) = if (mc.returnValue == THROW_EXCEPTION) mc else StandardMethodContract( + mc.arguments, NOT_NULL_VALUE) private fun getLiteralConstraint(argument: PsiExpression) = when (argument) { is PsiLiteralExpression -> ContractInferenceInterpreter.getLiteralConstraint(argument.getFirstChild().node.elementType) @@ -105,7 +106,7 @@ internal data class DelegationContract(internal val expression: ExpressionRange, internal data class SideEffectFilter(internal val expressionsToCheck: List, internal val contracts: List) : PreContract { - override fun toContracts(method: PsiMethod, body: () -> PsiCodeBlock): List { + override fun toContracts(method: PsiMethod, body: () -> PsiCodeBlock): List { if (expressionsToCheck.any { d -> mayHaveSideEffects(body(), d) }) { return emptyList() } @@ -120,16 +121,16 @@ internal data class NegatingContract(internal val negated: PreContract) : PreCon override fun toContracts(method: PsiMethod, body: () -> PsiCodeBlock) = negated.toContracts(method, body).mapNotNull(::negateContract) } -private fun negateContract(c: MethodContract): MethodContract? { +private fun negateContract(c: StandardMethodContract): StandardMethodContract? { val ret = c.returnValue - return if (ret == TRUE_VALUE || ret == FALSE_VALUE) MethodContract(c.arguments, negateConstraint(ret)) else null + return if (ret == TRUE_VALUE || ret == FALSE_VALUE) StandardMethodContract(c.arguments, negateConstraint(ret)) else null } @Suppress("EqualsOrHashCode") internal data class MethodCallContract(internal val call: ExpressionRange, internal val states: List>) : PreContract { override fun hashCode() = call.hashCode() * 31 + states.flatten().map { it.ordinal }.hashCode() - override fun toContracts(method: PsiMethod, body: () -> PsiCodeBlock): List { + override fun toContracts(method: PsiMethod, body: () -> PsiCodeBlock): List { val target = (call.restoreExpression(body()) as PsiMethodCallExpression?)?.resolveMethod() if (target != null && NullableNotNullManager.isNotNull(target)) { return ContractInferenceInterpreter.toContracts(states.map { it.toTypedArray() }, NOT_NULL_VALUE) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSet.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSet.java index 306c91c01bd2..56aea001e759 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSet.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSet.java @@ -15,10 +15,12 @@ */ package com.intellij.codeInspection.dataFlow.rangeSet; -import com.intellij.psi.JavaTokenType; +import com.intellij.codeInspection.dataFlow.value.DfaConstValue; +import com.intellij.codeInspection.dataFlow.value.DfaRangeValue; +import com.intellij.codeInspection.dataFlow.value.DfaRelationValue; +import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.psi.PsiPrimitiveType; import com.intellij.psi.PsiType; -import com.intellij.psi.tree.IElementType; import com.intellij.util.ThreeState; import org.jetbrains.annotations.Nullable; @@ -120,31 +122,31 @@ public abstract class LongRangeSet { * @param relation relation to be applied to current set (JavaTokenType.EQEQ/NE/GT/GE/LT/LE) * @return new set or null if relation is unsupported */ - public LongRangeSet fromRelation(IElementType relation) { - if (isEmpty()) return null; - if (JavaTokenType.EQEQ.equals(relation)) { - return this; + public LongRangeSet fromRelation(@Nullable DfaRelationValue.RelationType relation) { + if (isEmpty() || relation == null) return null; + switch (relation) { + case EQ: + return this; + case NE: { + long min = min(); + if (min == max()) return all().without(min); + return all(); + } + case GT: { + long min = min(); + return min == Long.MAX_VALUE ? empty() : range(min + 1, Long.MAX_VALUE); + } + case GE: + return range(min(), Long.MAX_VALUE); + case LE: + return range(Long.MIN_VALUE, max()); + case LT: { + long max = max(); + return max == Long.MIN_VALUE ? empty() : range(Long.MIN_VALUE, max - 1); + } + default: + return null; } - if (JavaTokenType.NE.equals(relation)) { - long min = min(); - if (min == max()) return all().without(min); - return all(); - } - if (JavaTokenType.GT.equals(relation)) { - long min = min(); - return min == Long.MAX_VALUE ? empty() : range(min + 1, Long.MAX_VALUE); - } - if (JavaTokenType.GE.equals(relation)) { - return range(min(), Long.MAX_VALUE); - } - if (JavaTokenType.LE.equals(relation)) { - return range(Long.MIN_VALUE, max()); - } - if (JavaTokenType.LT.equals(relation)) { - long max = max(); - return max == Long.MIN_VALUE ? empty() : range(Long.MIN_VALUE, max - 1); - } - return null; } /** @@ -326,6 +328,17 @@ public abstract class LongRangeSet { return null; } + @Nullable + public static LongRangeSet fromDfaValue(DfaValue value) { + if (value instanceof DfaRangeValue) { + return ((DfaRangeValue)value).getValue(); + } + if (value instanceof DfaConstValue) { + return fromConstant(((DfaConstValue)value).getValue()); + } + return null; + } + /** * Creates a new set which contains all the numbers between from (inclusive) and to (inclusive) * diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRangeValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRangeValue.java index 47825a92cf30..f2a56c182e14 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRangeValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRangeValue.java @@ -42,6 +42,11 @@ public class DfaRangeValue extends DfaValue { return myValue; } + @Override + public String toString() { + return myValue.toString(); + } + public static class Factory { private Map myValues = new HashMap<>(); private DfaValueFactory myFactory; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java index c77b320603ec..029208ed5209 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java @@ -24,117 +24,130 @@ */ package com.intellij.codeInspection.dataFlow.value; -import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Trinity; +import com.intellij.psi.JavaTokenType; import com.intellij.psi.tree.IElementType; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; - -import static com.intellij.psi.JavaTokenType.*; +import java.util.Map; public class DfaRelationValue extends DfaValue { + @Override + public DfaRelationValue createNegated() { + return myFactory.getRelationFactory().createCanonicalRelation(myLeftOperand, myRelation.getNegated(), myRightOperand); + } + private DfaValue myLeftOperand; private DfaValue myRightOperand; - private IElementType myRelation; - private boolean myIsNegated; + private RelationType myRelation; - public static class Factory { - private final DfaRelationValue mySharedInstance; - private final HashMap> myStringToObject; - private final DfaValueFactory myFactory; + public enum RelationType { + LE("<="), LT("<"), GE(">="), GT(">"), EQ("=="), NE("!="), + /** + * Value on the left belongs to the class of values defined on the right. + * Currently used to represent: + * - instanceof (DfaValue IS DfaTypeValue) + * - optional presense (DfaValue IS DfaOptionalValue) + */ + IS("is"), + /** + * Value on the left does not belong to the class of values defined on the right (opposite to IS). + */ + IS_NOT("isn't"); - Factory(DfaValueFactory factory) { - myFactory = factory; - mySharedInstance = new DfaRelationValue(factory); - myStringToObject = new HashMap<>(); + private final String myName; + + RelationType(String name) { + myName = name; } - public DfaRelationValue createRelation(DfaValue dfaLeft, DfaValue dfaRight, IElementType relation, boolean negated) { - if (PLUS == relation) return null; + @NotNull + public RelationType getNegated() { + switch (this) { + case LE: + return GT; + case LT: + return GE; + case GE: + return LT; + case GT: + return LE; + case EQ: + return NE; + case NE: + return EQ; + case IS: + return IS_NOT; + case IS_NOT: + return IS; + } + throw new InternalError("Unexpected enum value: " + this); + } - if (dfaLeft instanceof DfaVariableValue || dfaLeft instanceof DfaBoxedValue || dfaLeft instanceof DfaUnboxedValue - || dfaRight instanceof DfaVariableValue || dfaRight instanceof DfaBoxedValue || dfaRight instanceof DfaUnboxedValue) { - if (!(dfaLeft instanceof DfaVariableValue || dfaLeft instanceof DfaBoxedValue || dfaLeft instanceof DfaUnboxedValue)) { - return createRelation(dfaRight, dfaLeft, getSymmetricOperation(relation), negated); - } - - return createCanonicalRelation(relation, negated, dfaLeft, dfaRight); - } - if (dfaLeft instanceof DfaTypeValue && ((DfaTypeValue)dfaLeft).isNotNull() && dfaRight instanceof DfaConstValue) { - return createCanonicalRelation(relation, negated, dfaLeft, dfaRight); - } - else if (dfaRight instanceof DfaTypeValue && ((DfaTypeValue)dfaRight).isNotNull() && dfaLeft instanceof DfaConstValue) { - return createCanonicalRelation(relation, negated, dfaRight, dfaLeft); - } - else { - return null; + @Nullable + public RelationType getFlipped() { + switch (this) { + case LE: + return GE; + case LT: + return GT; + case GE: + return LE; + case GT: + return LT; + case EQ: + case NE: + return this; + default: + return null; } } - private DfaRelationValue createCanonicalRelation(IElementType relation, - boolean negated, - @NotNull final DfaValue dfaLeft, - @NotNull final DfaValue dfaRight) { - // To canonical form. - if (NE == relation) { - relation = EQEQ; - negated = !negated; - } - else if (LT == relation) { - relation = GE; - negated = !negated; - } - else if (LE == relation) { - relation = GT; - negated = !negated; - } - - mySharedInstance.myLeftOperand = dfaLeft; - mySharedInstance.myRightOperand = dfaRight; - mySharedInstance.myRelation = relation; - mySharedInstance.myIsNegated = negated; - - String id = mySharedInstance.toString(); - ArrayList conditions = myStringToObject.get(id); - if (conditions == null) { - conditions = new ArrayList<>(); - myStringToObject.put(id, conditions); - } - else { - for (DfaRelationValue rel : conditions) { - if (rel.hardEquals(mySharedInstance)) return rel; - } - } - - DfaRelationValue result = new DfaRelationValue(dfaLeft, dfaRight, relation, negated, myFactory); - conditions.add(result); - return result; + @Override + public String toString() { + return myName; } + @Nullable + public static RelationType fromElementType(IElementType type) { + if(JavaTokenType.EQEQ.equals(type)) { + return EQ; + } + if(JavaTokenType.NE.equals(type)) { + return NE; + } + if(JavaTokenType.LT.equals(type)) { + return LT; + } + if(JavaTokenType.GT.equals(type)) { + return GT; + } + if(JavaTokenType.LE.equals(type)) { + return LE; + } + if(JavaTokenType.GE.equals(type)) { + return GE; + } + if(JavaTokenType.INSTANCEOF_KEYWORD.equals(type)) { + return IS; + } + return null; + } + + public static RelationType equivalence(boolean equal) { + return equal ? EQ : NE; + } } - public static IElementType getSymmetricOperation(IElementType sign) { - if (LT == sign) return GT; - if (GE == sign) return LE; - if (GT == sign) return LT; - if (LE == sign) return GE; - return sign; - } - - private DfaRelationValue(DfaValueFactory factory) { - super(factory); - } - - private DfaRelationValue(DfaValue myLeftOperand, DfaValue myRightOperand, IElementType myRelation, boolean myIsNegated, + private DfaRelationValue(DfaValue leftOperand, DfaValue rightOperand, RelationType relationType, DfaValueFactory factory) { super(factory); - this.myLeftOperand = myLeftOperand; - this.myRightOperand = myRightOperand; - this.myRelation = myRelation; - this.myIsNegated = myIsNegated; + this.myLeftOperand = leftOperand; + this.myRightOperand = rightOperand; + this.myRelation = relationType; } public DfaValue getLeftOperand() { @@ -145,52 +158,59 @@ public class DfaRelationValue extends DfaValue { return myRightOperand; } - public boolean isNegated() { - return myIsNegated; - } + public static class Factory { + private final Map, DfaRelationValue> myValues; + private final DfaValueFactory myFactory; - @Override - public DfaValue createNegated() { - return myFactory.getRelationFactory().createRelation(myLeftOperand, myRightOperand, myRelation, !myIsNegated); - } + Factory(DfaValueFactory factory) { + myFactory = factory; + myValues = new HashMap<>(); + } - private boolean hardEquals(DfaRelationValue rel) { - return Comparing.equal(rel.myLeftOperand,myLeftOperand) - && Comparing.equal(rel.myRightOperand,myRightOperand) && - rel.myRelation == myRelation && - rel.myIsNegated == myIsNegated; + public DfaRelationValue createRelation(DfaValue dfaLeft, RelationType relationType, DfaValue dfaRight) { + if ((relationType == RelationType.IS || relationType == RelationType.IS_NOT) && dfaRight instanceof DfaOptionalValue) { + return createCanonicalRelation(dfaLeft, relationType, dfaRight); + } + if (dfaLeft instanceof DfaVariableValue || dfaLeft instanceof DfaBoxedValue || dfaLeft instanceof DfaUnboxedValue + || dfaRight instanceof DfaVariableValue || dfaRight instanceof DfaBoxedValue || dfaRight instanceof DfaUnboxedValue) { + if (!(dfaLeft instanceof DfaVariableValue || dfaLeft instanceof DfaBoxedValue || dfaLeft instanceof DfaUnboxedValue)) { + RelationType flipped = relationType.getFlipped(); + return flipped == null ? null : createCanonicalRelation(dfaRight, flipped, dfaLeft); + } + return createCanonicalRelation(dfaLeft, relationType, dfaRight); + } + if (dfaLeft instanceof DfaTypeValue && dfaRight instanceof DfaConstValue) { + return createCanonicalRelation(DfaUnknownValue.getInstance(), relationType, dfaRight); + } + else if (dfaRight instanceof DfaTypeValue && dfaLeft instanceof DfaConstValue) { + return createCanonicalRelation(DfaUnknownValue.getInstance(), relationType, dfaLeft); + } + return null; + } + + @NotNull + private DfaRelationValue createCanonicalRelation(@NotNull final DfaValue dfaLeft, + @NotNull RelationType relationType, + @NotNull final DfaValue dfaRight) { + return myValues.computeIfAbsent(Trinity.create(dfaLeft, dfaRight, relationType), + k -> new DfaRelationValue(dfaLeft, dfaRight, relationType, myFactory)); + } } public boolean isEquality() { - return myRelation == EQEQ && !myIsNegated; + return myRelation == RelationType.EQ; } public boolean isNonEquality() { - return myRelation == EQEQ && myIsNegated || myRelation == GT && !myIsNegated || myRelation == GE && myIsNegated; + return myRelation == RelationType.NE || myRelation == RelationType.GT || myRelation == RelationType.LT; } - /** - * @return comparison operation (GT, GE, LE, LT, EQEQ, NE) if this relation represents comparison, null otherwise - */ - @Nullable - public IElementType getComparisonOperation() { - if(myRelation == GT) { - return myIsNegated ? LE : GT; - } - if(myRelation == GE) { - return myIsNegated ? LT : GE; - } - if(myRelation == EQEQ) { - return myIsNegated ? NE : EQEQ; - } - return null; - } - - public boolean isInstanceOf() { - return myRelation == INSTANCEOF_KEYWORD; + @NotNull + public RelationType getRelation() { + return myRelation; } @NonNls public String toString() { - return (isNegated() ? "not " : "") + myLeftOperand + " " + myRelation + " " + myRightOperand; + return myLeftOperand + " " + myRelation + " " + myRightOperand; } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValueFactory.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValueFactory.java index fd29e0c5b37a..ad65d18be27e 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValueFactory.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValueFactory.java @@ -24,13 +24,13 @@ */ package com.intellij.codeInspection.dataFlow.value; -import com.intellij.codeInspection.dataFlow.DfaControlTransferValue; -import com.intellij.codeInspection.dataFlow.Nullness; -import com.intellij.codeInspection.dataFlow.TransferTarget; -import com.intellij.codeInspection.dataFlow.Trap; +import com.intellij.codeInspection.dataFlow.*; +import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet; +import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.FList; @@ -105,6 +105,93 @@ public class DfaValueFactory { return getConstFactory().create(literal); } + @NotNull + public DfaValue createStringLength(DfaValue value) { + if (value instanceof DfaVariableValue) { + DfaVariableValue variableValue = (DfaVariableValue)value; + PsiType type = variableValue.getVariableType(); + if (type != null && type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { + PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(type); + if (psiClass != null) { + PsiMethod[] lengthMethods = psiClass.findMethodsByName("length", false); + if (lengthMethods.length == 1) { + return getVarFactory().createVariableValue(lengthMethods[0], PsiType.INT, false, variableValue); + } + } + } + } + if(value instanceof DfaConstValue) { + Object str = ((DfaConstValue)value).getValue(); + if(str instanceof String) { + return getConstFactory().createFromValue(((String)str).length(), PsiType.INT, null); + } + } + return DfaUnknownValue.getInstance(); + } + + /** + * Create condition (suitable to pass into {@link DfaMemoryState#applyCondition(DfaValue)}), + * evaluating it statically if possible. + * + * @param dfaLeft left operand + * @param relationType relation + * @param dfaRight right operand + * @return resulting condition: either {@link DfaRelationValue} or {@link DfaConstValue} (true or false) or {@link DfaUnknownValue}. + */ + @NotNull + public DfaValue createCondition(DfaValue dfaLeft, RelationType relationType, DfaValue dfaRight) { + DfaConstValue value = tryEvaluate(dfaLeft, relationType, dfaRight); + if (value != null) return value; + DfaRelationValue relation = getRelationFactory().createRelation(dfaLeft, relationType, dfaRight); + if (relation != null) return relation; + return DfaUnknownValue.getInstance(); + } + + @Nullable + private DfaConstValue tryEvaluate(DfaValue dfaLeft, RelationType relationType, DfaValue dfaRight) { + if(dfaRight instanceof DfaTypeValue && dfaLeft == getConstFactory().getNull()) { + return tryEvaluate(dfaRight, relationType, dfaLeft); + } + if (dfaLeft instanceof DfaTypeValue && dfaRight == getConstFactory().getNull() && ((DfaTypeValue)dfaLeft).isNotNull()) { + if (relationType == RelationType.EQ) { + return getConstFactory().getFalse(); + } + if (relationType == RelationType.NE) { + return getConstFactory().getTrue(); + } + } + + if(dfaLeft instanceof DfaOptionalValue && dfaRight instanceof DfaOptionalValue) { + if(relationType == RelationType.IS) { + return getBoolean(dfaLeft == dfaRight); + } else if(relationType == RelationType.IS_NOT) { + return getBoolean(dfaLeft != dfaRight); + } + } + + LongRangeSet leftRange = LongRangeSet.fromDfaValue(dfaLeft); + LongRangeSet rightRange = LongRangeSet.fromDfaValue(dfaRight); + if (leftRange != null && rightRange != null) { + LongRangeSet constraint = rightRange.fromRelation(relationType); + if (constraint != null && !constraint.intersects(leftRange)) { + return getConstFactory().getFalse(); + } + LongRangeSet revConstraint = rightRange.fromRelation(relationType.getNegated()); + if (revConstraint != null && !revConstraint.intersects(leftRange)) { + return getConstFactory().getTrue(); + } + } + + if(dfaLeft instanceof DfaConstValue && dfaRight instanceof DfaConstValue && + (relationType == RelationType.EQ || relationType == RelationType.NE)) { + return getBoolean(dfaLeft == dfaRight ^ + !DfaUtil.isNaN(((DfaConstValue)dfaLeft).getValue()) ^ + relationType == RelationType.EQ); + } + + return null; + } + public DfaConstValue getBoolean(boolean value) { return value ? getConstFactory().getTrue() : getConstFactory().getFalse(); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java index 05c4bdd1babc..05613f764bac 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java @@ -273,10 +273,10 @@ public class DfaVariableValue extends DfaValue { public boolean isFlushableByCalls() { if (myVariable instanceof PsiLocalVariable || myVariable instanceof PsiParameter) return false; - if (myVariable instanceof PsiVariable && myVariable.hasModifierProperty(PsiModifier.FINAL)) { + if (myVariable instanceof PsiVariable && myVariable.hasModifierProperty(PsiModifier.FINAL) || + myVariable instanceof PsiMethod && MethodUtils.isStringLength((PsiMethod)myVariable)) { return myQualifier != null && myQualifier.isFlushableByCalls(); } - if (myVariable instanceof PsiMethod && MethodUtils.isStringLength((PsiMethod)myVariable)) return false; return true; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/defUse/DefUseInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/defUse/DefUseInspectionBase.java index 9d62dc7685ac..986d72a86368 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/defUse/DefUseInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/defUse/DefUseInspectionBase.java @@ -155,21 +155,21 @@ public class DefUseInspectionBase extends BaseJavaBatchLocalInspectionTool { myReportInitializer = new JCheckBox(InspectionsBundle.message("inspection.unused.assignment.option2")); myReportInitializer.setSelected(REPORT_REDUNDANT_INITIALIZER); - myReportInitializer.getModel().addChangeListener(e -> REPORT_REDUNDANT_INITIALIZER = myReportInitializer.isSelected()); + myReportInitializer.getModel().addItemListener(e -> REPORT_REDUNDANT_INITIALIZER = myReportInitializer.isSelected()); gc.insets = JBUI.insetsBottom(15); gc.gridy = 0; add(myReportInitializer, gc); myReportPrefix = new JCheckBox(InspectionsBundle.message("inspection.unused.assignment.option")); myReportPrefix.setSelected(REPORT_PREFIX_EXPRESSIONS); - myReportPrefix.getModel().addChangeListener(e -> REPORT_PREFIX_EXPRESSIONS = myReportPrefix.isSelected()); + myReportPrefix.getModel().addItemListener(e -> REPORT_PREFIX_EXPRESSIONS = myReportPrefix.isSelected()); gc.insets = JBUI.emptyInsets(); gc.gridy++; add(myReportPrefix, gc); myReportPostfix = new JCheckBox(InspectionsBundle.message("inspection.unused.assignment.option1")); myReportPostfix.setSelected(REPORT_POSTFIX_EXPRESSIONS); - myReportPostfix.getModel().addChangeListener(e -> REPORT_POSTFIX_EXPRESSIONS = myReportPostfix.isSelected()); + myReportPostfix.getModel().addItemListener(e -> REPORT_POSTFIX_EXPRESSIONS = myReportPostfix.isSelected()); gc.weighty = 1; gc.gridy++; add(myReportPostfix, gc); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/java19modules/Java9RedundantRequiresStatementInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/java19modules/Java9RedundantRequiresStatementInspection.java index c1dd08665ebd..7d1bc06c79d5 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/java19modules/Java9RedundantRequiresStatementInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/java19modules/Java9RedundantRequiresStatementInspection.java @@ -239,7 +239,7 @@ public class Java9RedundantRequiresStatementInspection extends GlobalJavaBatchIn if (importList != null) { RefModule refModule = refFile.getModule(); if (refModule != null) { - Set packageNames = getImportedPackages(refModule); + Set packageNames = getImportedPackages(refModule, refFile); if (packageNames != DONT_COLLECT_PACKAGES) { PsiImportStatementBase[] statements = importList.getAllImportStatements(); for (PsiImportStatementBase statement : statements) { @@ -270,10 +270,10 @@ public class Java9RedundantRequiresStatementInspection extends GlobalJavaBatchIn } @NotNull - private static Set getImportedPackages(@NotNull RefModule refModule) { + private static Set getImportedPackages(@NotNull RefModule refModule, @NotNull RefFile refFile) { Set importedPackages = refModule.getUserData(IMPORTED_JAVA_PACKAGES); if (importedPackages == null) { - PsiJavaModule javaModule = JavaModuleGraphUtil.findDescriptorByModule(refModule.getModule()); + PsiJavaModule javaModule = JavaModuleGraphUtil.findDescriptorByElement(refFile.getElement()); importedPackages = javaModule != null ? new THashSet<>() : DONT_COLLECT_PACKAGES; refModule.putUserData(IMPORTED_JAVA_PACKAGES, importedPackages); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java index f6fe9f080b14..75be48c46248 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java @@ -65,7 +65,7 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { private Set myInTypeReferences; private Set myInstanceReferences; private List myClassExporters; - private RefModule myRefModule; + private final RefModule myRefModule; RefClassImpl(PsiClass psiClass, RefManager manager) { super(psiClass, manager); @@ -89,9 +89,10 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { } else if (psiParent instanceof PsiJavaFile) { PsiJavaFile psiFile = (PsiJavaFile) psiParent; String packageName = psiFile.getPackageName(); - if (!"".equals(packageName)) { + if (!packageName.isEmpty()) { ((RefPackageImpl)getRefJavaManager().getPackage(packageName)).add(this); - } else { + } + else { ((RefPackageImpl)getRefJavaManager().getDefaultPackage()).add(this); } } @@ -373,7 +374,7 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { return myInTypeReferences; } - public void addTypeReference(RefJavaElement from) { + void addTypeReference(RefJavaElement from) { if (from != null) { if (myInTypeReferences == null){ myInTypeReferences = new THashSet<>(1); @@ -391,7 +392,7 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { return myInstanceReferences; } - public void addInstanceReference(RefElement from) { + void addInstanceReference(RefElement from) { if (myInstanceReferences == null){ myInstanceReferences = new THashSet<>(1); } @@ -410,7 +411,7 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { myConstructors.add(refConstructor); } - public void addLibraryOverrideMethod(RefMethod refMethod) { + void addLibraryOverrideMethod(RefMethod refMethod) { if (myOverridingMethods == null){ myOverridingMethods = new ArrayList<>(2); } @@ -457,7 +458,7 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { @Nullable - public static RefClass classFromExternalName(RefManager manager, String externalName) { + static RefClass classFromExternalName(RefManager manager, String externalName) { return (RefClass) manager.getReference(ClassUtil.findPsiClass(PsiManager.getInstance(manager.getProject()), externalName)); } @@ -485,7 +486,7 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { } } - protected void methodRemoved(RefMethod method) { + void methodRemoved(RefMethod method) { getConstructors().remove(method); getLibraryMethods().remove(method); @@ -542,7 +543,7 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { return false; } - public void addClassExporter(RefJavaElement exporter) { + void addClassExporter(RefJavaElement exporter) { if (myClassExporters == null) myClassExporters = new ArrayList<>(1); if (myClassExporters.contains(exporter)) return; myClassExporters.add(exporter); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java index 0e65a9e144dd..f27305dde4e2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java @@ -142,17 +142,14 @@ public class RefFieldImpl extends RefJavaElementImpl implements RefField { @Override public String getExternalName() { - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - PsiField psiField = getElement(); - return psiField != null ? PsiFormatUtil.getExternalName(psiField) : null; - } + return ApplicationManager.getApplication().runReadAction((Computable)() -> { + PsiField psiField = getElement(); + return psiField != null ? PsiFormatUtil.getExternalName(psiField) : null; }); } @Nullable - public static RefField fieldFromExternalName(RefManager manager, String externalName) { + static RefField fieldFromExternalName(RefManager manager, String externalName) { return (RefField)manager.getReference(findPsiField(PsiManager.getInstance(manager.getProject()), externalName)); } @@ -161,9 +158,9 @@ public class RefFieldImpl extends RefJavaElementImpl implements RefField { int classNameDelimiter = externalName.lastIndexOf(' '); if (classNameDelimiter > 0 && classNameDelimiter < externalName.length() - 1) { final String className = externalName.substring(0, classNameDelimiter); - final String fieldName = externalName.substring(classNameDelimiter + 1); final PsiClass psiClass = ClassUtil.findPsiClass(manager, className); if (psiClass != null) { + final String fieldName = externalName.substring(classNameDelimiter + 1); return psiClass.findFieldByName(fieldName, false); } } @@ -173,8 +170,7 @@ public class RefFieldImpl extends RefJavaElementImpl implements RefField { @Override public boolean isSuspicious() { if (isEntry()) return false; - if (super.isSuspicious()) return true; - return isUsedForReading() != isUsedForWriting(); + return super.isSuspicious() || isUsedForReading() != isUsedForWriting(); } @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java index 80af5c532a9a..2504179c1bb6 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java @@ -63,12 +63,7 @@ public class RefImplicitConstructorImpl extends RefMethodImpl implements RefImpl @Override public boolean isValid() { - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - return getOwnerClass().isValid(); - } - }).booleanValue(); + return ApplicationManager.getApplication().runReadAction((Computable)getOwnerClass()::isValid).booleanValue(); } @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java index 4eb62d7cf4d1..071943e73281 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java @@ -59,10 +59,6 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa } } - protected RefJavaElementImpl(PsiFile file, RefManager manager) { - super(file, manager); - } - protected RefJavaElementImpl(PsiModifierListOwner elem, RefManager manager) { super(getName(elem), elem, manager); @@ -85,7 +81,7 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa return myOutTypeReferences; } - public void addOutTypeRefernce(RefClass refClass){ + void addOutTypeRefernce(RefClass refClass){ if (myOutTypeReferences == null){ myOutTypeReferences = new THashSet<>(); } @@ -137,7 +133,7 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa return checkFlag(IS_USES_DEPRECATION_MASK); } - public void setUsesDeprecatedApi(boolean usesDeprecatedApi) { + void setUsesDeprecatedApi(boolean usesDeprecatedApi) { setFlag(usesDeprecatedApi, IS_USES_DEPRECATION_MASK); } @@ -154,7 +150,7 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa return checkFlag(IS_SYNTHETIC_JSP_ELEMENT_MASK); } - public void setSyntheticJSP(boolean b) { + private void setSyntheticJSP(boolean b) { setFlag(b, IS_SYNTHETIC_JSP_ELEMENT_MASK); } @@ -262,7 +258,7 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa getRefManager().fireNodeMarkedReferenced(this, refFrom, false, forReading, forWriting); } - protected void setUsedQualifiedOutsidePackageFlag(RefElementImpl refFrom, PsiReferenceExpression expressionFrom) { + void setUsedQualifiedOutsidePackageFlag(RefElementImpl refFrom, PsiReferenceExpression expressionFrom) { if (!checkFlag(IS_USED_QUALIFIED_OUTSIDE_PACKAGE_MASK) && expressionFrom != null && expressionFrom.isQualified() && RefJavaUtil.getPackage(refFrom) != RefJavaUtil.getPackage(this)) { setFlag(true, IS_USED_QUALIFIED_OUTSIDE_PACKAGE_MASK); @@ -273,7 +269,7 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa return checkFlag(IS_USED_QUALIFIED_OUTSIDE_PACKAGE_MASK); } - protected RefJavaManager getRefJavaManager() { + RefJavaManager getRefJavaManager() { return getRefManager().getExtension(RefJavaManager.MANAGER); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java index bb5fb6ced378..791302557718 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java @@ -15,10 +15,7 @@ */ package com.intellij.codeInspection.reference; -import com.intellij.codeInspection.BatchSuppressManager; -import com.intellij.codeInspection.InspectionProfileEntry; -import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.codeInspection.SuppressionUtil; +import com.intellij.codeInspection.*; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase; import com.intellij.codeInspection.ex.*; import com.intellij.openapi.diagnostic.Logger; @@ -119,10 +116,7 @@ public class RefJavaManagerImpl extends RefJavaManager { if (tool.isTestEntryPoints()) return true; final PsiElement element = refElement.getElement(); final VirtualFile file = PsiUtilCore.getVirtualFile(element); - if (file != null) { - return !ProjectRootManager.getInstance(element.getProject()).getFileIndex().isInTestSourceContent(file); - } - return false; + return file != null && !ProjectRootManager.getInstance(element.getProject()).getFileIndex().isInTestSourceContent(file); } @Nullable @@ -250,7 +244,7 @@ public class RefJavaManagerImpl extends RefJavaManager { if (elem instanceof PsiClass) { return new RefClassImpl((PsiClass)elem, myRefManager); } - else if (elem instanceof PsiMethod) { + if (elem instanceof PsiMethod) { final PsiMethod method = (PsiMethod)elem; final RefElement ref = myRefManager.getReference(method.getContainingClass(), true); if (ref instanceof RefClass) { @@ -268,7 +262,7 @@ public class RefJavaManagerImpl extends RefJavaManager { return new RefJavaFileImpl((PsiJavaFile)elem, myRefManager); } else if (elem instanceof PsiJavaModule) { - return new RefJavaModuleImpl(((PsiJavaModule)elem), myRefManager); + return new RefJavaModuleImpl((PsiJavaModule)elem, myRefManager); } return null; } @@ -282,16 +276,16 @@ public class RefJavaManagerImpl extends RefJavaManager { if (METHOD.equals(type)) { return RefMethodImpl.methodFromExternalName(myRefManager, fqName); } - else if (CLASS.equals(type)) { + if (CLASS.equals(type)) { return RefClassImpl.classFromExternalName(myRefManager, fqName); } - else if (FIELD.equals(type)) { + if (FIELD.equals(type)) { return RefFieldImpl.fieldFromExternalName(myRefManager, fqName); } - else if (PARAMETER.equals(type)) { + if (PARAMETER.equals(type)) { return RefParameterImpl.parameterFromExternalName(myRefManager, fqName); } - else if (PACKAGE.equals(type)) { + if (PACKAGE.equals(type)) { return RefPackageImpl.packageFromFQName(myRefManager, fqName); } return null; @@ -303,22 +297,22 @@ public class RefJavaManagerImpl extends RefJavaManager { if (ref instanceof RefImplicitConstructor) { return IMPLICIT_CONSTRUCTOR; } - else if (ref instanceof RefMethod) { + if (ref instanceof RefMethod) { return METHOD; } - else if (ref instanceof RefClass) { + if (ref instanceof RefClass) { return CLASS; } - else if (ref instanceof RefField) { + if (ref instanceof RefField) { return FIELD; } - else if (ref instanceof RefParameter) { + if (ref instanceof RefParameter) { return PARAMETER; } - else if (ref instanceof RefPackage) { + if (ref instanceof RefPackage) { return PACKAGE; } - else if (ref instanceof RefJavaModule) { + if (ref instanceof RefJavaModule) { return JAVA_MODULE; } return null; @@ -372,21 +366,6 @@ public class RefJavaManagerImpl extends RefJavaManager { if (isEntryPoint(refElement)) { getEntryPointsManager().addEntryPoint(refElement, false); } - - /*if (psiElement instanceof PsiClass) { - PsiClass psiClass = (PsiClass)psiElement; - - EntryPointsManager entryPointsManager = getEntryPointsManager(); - if (psiClass.isAnnotationType()){ - entryPointsManager.addEntryPoint(refElement, false); - for (PsiMethod psiMethod : psiClass.getMethods()) { - entryPointsManager.addEntryPoint(myRefManager.getReference(psiMethod), false); - } - } - else if (psiClass.isEnum()) { - entryPointsManager.addEntryPoint(refElement, false); - } - }*/ } private static void appendPackageElement(final Element element, final String packageName) { @@ -420,7 +399,7 @@ public class RefJavaManagerImpl extends RefJavaManager { private class MyJavaElementVisitor extends JavaElementVisitor { private final RefJavaUtil myRefUtil; - public MyJavaElementVisitor() { + MyJavaElementVisitor() { myRefUtil = RefJavaUtil.getInstance(); } @@ -488,9 +467,9 @@ public class RefJavaManagerImpl extends RefJavaManager { super.visitDocComment(comment); final PsiDocTag[] tags = comment.getTags(); for (PsiDocTag tag : tags) { - if (Comparing.strEqual(tag.getName(), SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME)) { + if (Comparing.strEqual(tag.getName(), SuppressionUtilCore.SUPPRESS_INSPECTIONS_TAG_NAME)) { final PsiElement[] dataElements = tag.getDataElements(); - if (dataElements != null && dataElements.length > 0) { + if (dataElements.length > 0) { final PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(comment, PsiModifierListOwner.class); if (listOwner != null) { final RefElementImpl element = (RefElementImpl)myRefManager.getReference(listOwner); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaModuleImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaModuleImpl.java index 69d8ff16e6ca..f1deb3ae07f2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaModuleImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaModuleImpl.java @@ -18,6 +18,7 @@ package com.intellij.codeInspection.reference; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.psi.*; +import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,14 +37,14 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule { private Map> myExportedPackageNames; private List myRequiredModules; - public RefJavaModuleImpl(@NotNull PsiJavaModule javaModule, @NotNull RefManagerImpl manager) { + RefJavaModuleImpl(@NotNull PsiJavaModule javaModule, @NotNull RefManagerImpl manager) { super(javaModule.getName(), javaModule, manager); myRefModule = manager.getRefModule(ModuleUtilCore.findModuleForPsiElement(javaModule)); } @Override protected void initialize() { - + ((RefModuleImpl)myRefModule).add(this); } @Override @@ -74,6 +75,7 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule { return myExportedPackageNames != null ? myExportedPackageNames : Collections.emptyMap(); } + @Override @NotNull public List getRequiredModules() { return myRequiredModules != null ? myRequiredModules : Collections.emptyList(); @@ -115,7 +117,49 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule { } } } - ((RefModuleImpl)myRefModule).add(this); + for (PsiProvidesStatement statement : javaModule.getProvides()) { + final PsiJavaCodeReferenceElement interfaceReference = statement.getInterfaceReference(); + final PsiReferenceList implementationList = statement.getImplementationList(); + if (interfaceReference != null && implementationList != null) { + final PsiElement providerInterface = interfaceReference.resolve(); + if (providerInterface instanceof PsiClass) { + final RefElement refInterface = getRefManager().getReference(providerInterface); + if (refInterface instanceof RefJavaElementImpl) { + for (PsiJavaCodeReferenceElement implementationReference : implementationList.getReferenceElements()) { + final PsiElement implementationClass = implementationReference.resolve(); + if (implementationClass instanceof PsiClass) { + RefElement refTargetElement = null; + PsiElement targetElement = getProviderMethod((PsiClass)implementationClass); + + if (targetElement == null) { + final RefElement refClass = getRefManager().getReference(implementationClass); + if (refClass instanceof RefClassImpl) { + final RefMethod refConstructor = ((RefClassImpl)refClass).getDefaultConstructor(); + if (refConstructor != null) { + final PsiModifierListOwner constructorElement = refConstructor.getElement(); + if (constructorElement != null && constructorElement.hasModifierProperty(PsiModifier.PUBLIC)) { + refTargetElement = refConstructor; + targetElement = constructorElement; + } + } + } + } + if (targetElement == null) { + targetElement = implementationClass; + } + if (refTargetElement == null) { + refTargetElement = getRefManager().getReference(targetElement); + } + if (refTargetElement != null) { + ((RefJavaElementImpl)refInterface) + .addReference(refTargetElement, targetElement, providerInterface, false, true, null); + } + } + } + } + } + } + } getRefManager().fireBuildReferences(this); } } @@ -150,4 +194,12 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule { } return !exportedPackages.isEmpty() ? exportedPackages : Collections.emptyMap(); } + + @Nullable + private static PsiMethod getProviderMethod(@NotNull PsiClass psiClass) { + final PsiMethod[] methods = psiClass.findMethodsByName("provider", false); + return ContainerUtil.find(methods, m -> m.hasModifierProperty(PsiModifier.PUBLIC) && + m.hasModifierProperty(PsiModifier.STATIC) && + m.getParameterList().getParametersCount() == 0); + } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java index 31d19a3a5cfa..e49abfcbe2cf 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java @@ -146,7 +146,7 @@ public class RefJavaUtilImpl extends RefJavaUtil{ } final Collection exceptionTypes = body != null ? ExceptionUtil.collectUnhandledExceptions(body, topElement, false) - : Collections.emptyList(); + : Collections.emptyList(); RefElement refResolved = refFrom.getRefManager().getReference(interfaceMethod); if (refResolved instanceof RefMethodImpl) { for (final PsiClassType exceptionType : exceptionTypes) { @@ -301,7 +301,7 @@ public class RefJavaUtilImpl extends RefJavaUtil{ public RefClass getTopLevelClass(@NotNull RefElement refElement) { RefEntity refParent = refElement.getOwner(); - while (refParent != null && refParent instanceof RefElement && !(refParent instanceof RefFile)) { + while (refParent instanceof RefElement && !(refParent instanceof RefFile)) { refElement = (RefElementImpl)refParent; refParent = refParent.getOwner(); } @@ -458,13 +458,13 @@ public class RefJavaUtilImpl extends RefJavaUtil{ if (a == PsiModifier.PRIVATE) { return 0; } - else if (a == PsiModifier.PACKAGE_LOCAL) { + if (a == PsiModifier.PACKAGE_LOCAL) { return 1; } - else if (a == PsiModifier.PROTECTED) { + if (a == PsiModifier.PROTECTED) { return 2; } - else if (a == PsiModifier.PUBLIC) return 3; + if (a == PsiModifier.PUBLIC) return 3; return -1; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java index 441b6b8399c8..e75957048f19 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java @@ -88,7 +88,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { public List getChildren() { List superChildren = super.getChildren(); if (myParameters == null) return superChildren; - if (superChildren.isEmpty()) return Arrays.asList(myParameters); + if (superChildren.isEmpty()) return Arrays.asList(myParameters); List allChildren = new ArrayList<>(superChildren.size() + myParameters.length); allChildren.addAll(superChildren); @@ -426,17 +426,13 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { if (psiMethod instanceof SyntheticElement) { return psiMethod.getName(); } - else { - return PsiFormatUtil.formatMethod(psiMethod, - PsiSubstitutor.EMPTY, - PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, - PsiFormatUtilBase.SHOW_TYPE - ); - } + return PsiFormatUtil.formatMethod(psiMethod, + PsiSubstitutor.EMPTY, + PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, + PsiFormatUtilBase.SHOW_TYPE); }); - } else { - return super.getName(); } + return super.getName(); } @Override @@ -449,7 +445,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { } @Nullable - public static RefMethod methodFromExternalName(RefManager manager, String externalName) { + static RefMethod methodFromExternalName(RefManager manager, String externalName) { return (RefMethod) manager.getReference(findPsiMethod(PsiManager.getInstance(manager.getProject()), externalName)); } @@ -498,7 +494,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { return super.isSuspicious(); } - public void setReturnValueUsed(boolean value) { + void setReturnValueUsed(boolean value) { if (checkFlag(IS_RETURN_VALUE_USED_MASK) == value) return; setFlag(value, IS_RETURN_VALUE_USED_MASK); for (RefMethod refSuper : getSuperMethods()) { @@ -511,7 +507,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { return checkFlag(IS_RETURN_VALUE_USED_MASK); } - public void updateReturnValueTemplate(PsiExpression expression) { + void updateReturnValueTemplate(PsiExpression expression) { if (myReturnValueTemplate == null) return; if (!getSuperMethods().isEmpty()) { @@ -549,7 +545,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { } } - public void updateParameterValues(PsiExpression[] args) { + void updateParameterValues(PsiExpression[] args) { if (isExternalOverride()) return; if (!getSuperMethods().isEmpty()) { @@ -560,12 +556,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { final RefParameter[] params = getParameters(); if (params.length <= args.length && params.length > 0) { for (int i = 0; i < args.length; i++) { - RefParameter refParameter; - if (params.length <= i){ - refParameter = params[params.length - 1]; - } else { - refParameter = params[i]; - } + RefParameter refParameter = params.length <= i ? params[params.length - 1] : params[i]; ((RefParameterImpl)refParameter).updateTemplateValue(args[i]); } } @@ -667,12 +658,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { return checkFlag(IS_CALLED_ON_SUBCLASS_MASK); } - public void setCalledOnSubClass(boolean isCalledOnSubClass){ + void setCalledOnSubClass(boolean isCalledOnSubClass){ setFlag(isCalledOnSubClass, IS_CALLED_ON_SUBCLASS_MASK); } - - private static String extractMethodName(String methodSignature) { - final String returnTypeAndName = methodSignature.substring(0, methodSignature.indexOf('(')); - return returnTypeAndName.substring(returnTypeAndName.indexOf(' ') + 1); - } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefPackageImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefPackageImpl.java index 7108686654f8..f937d34a0a08 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefPackageImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefPackageImpl.java @@ -32,7 +32,7 @@ import javax.swing.*; public class RefPackageImpl extends RefEntityImpl implements RefPackage { - public RefPackageImpl(@NotNull String name, @NotNull RefManager refManager) { + RefPackageImpl(@NotNull String name, @NotNull RefManager refManager) { super(name, refManager); } @@ -45,7 +45,7 @@ public class RefPackageImpl extends RefEntityImpl implements RefPackage { } } - public static RefEntity packageFromFQName(final RefManager manager, final String name) { + static RefEntity packageFromFQName(final RefManager manager, final String name) { return manager.getExtension(RefJavaManager.MANAGER).getPackage(name); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefParameterImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefParameterImpl.java index d3f373ae6b94..c9859d3316c6 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefParameterImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefParameterImpl.java @@ -28,6 +28,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.util.PsiFormatUtilBase; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -106,7 +107,7 @@ public class RefParameterImpl extends RefJavaElementImpl implements RefParameter } } - public void updateTemplateValue(PsiExpression expression) { + void updateTemplateValue(PsiExpression expression) { if (myActualValueTemplate == null) return; String newTemplate = null; @@ -121,14 +122,16 @@ public class RefParameterImpl extends RefJavaElementImpl implements RefParameter if (psiField.hasModifierProperty(PsiModifier.STATIC) && psiField.hasModifierProperty(PsiModifier.FINAL) && psiField.getContainingClass().getQualifiedName() != null) { - newTemplate = PsiFormatUtil.formatVariable(psiField, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_CONTAINING_CLASS | PsiFormatUtil.SHOW_FQ_NAME, PsiSubstitutor.EMPTY); + newTemplate = PsiFormatUtil.formatVariable(psiField, PsiFormatUtilBase.SHOW_NAME | + PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_FQ_NAME, PsiSubstitutor.EMPTY); } } } if (myActualValueTemplate == VALUE_UNDEFINED) { myActualValueTemplate = newTemplate; - } else if (!Comparing.equal(myActualValueTemplate, newTemplate)) { + } + else if (!Comparing.equal(myActualValueTemplate, newTemplate)) { myActualValueTemplate = null; } } @@ -158,10 +161,9 @@ public class RefParameterImpl extends RefJavaElementImpl implements RefParameter } @Nullable - public static RefElement parameterFromExternalName(final RefManager manager, final String fqName) { + static RefElement parameterFromExternalName(final RefManager manager, final String fqName) { final int idx = fqName.lastIndexOf(' '); if (idx > 0) { - final String paramName = fqName.substring(idx + 1); final String method = fqName.substring(0, idx); final RefMethod refMethod = RefMethodImpl.methodFromExternalName(manager, method); if (refMethod != null) { @@ -169,6 +171,7 @@ public class RefParameterImpl extends RefJavaElementImpl implements RefParameter final PsiParameterList list = element.getParameterList(); final PsiParameter[] parameters = list.getParameters(); int paramIdx = 0; + final String paramName = fqName.substring(idx + 1); for (PsiParameter parameter : parameters) { final String name = parameter.getName(); if (name != null && name.equals(paramName)) { @@ -180,25 +183,4 @@ public class RefParameterImpl extends RefJavaElementImpl implements RefParameter } return null; } - - @Nullable - public static PsiParameter findPsiParameter(String fqName, final PsiManager manager) { - final int idx = fqName.lastIndexOf(' '); - if (idx > 0) { - final String paramName = fqName.substring(idx + 1); - final String method = fqName.substring(0, idx); - final PsiMethod psiMethod = RefMethodImpl.findPsiMethod(manager, method); - if (psiMethod != null) { - final PsiParameterList list = psiMethod.getParameterList(); - final PsiParameter[] parameters = list.getParameters(); - for (PsiParameter parameter : parameters) { - final String name = parameter.getName(); - if (name != null && name.equals(paramName)) { - return parameter; - } - } - } - } - return null; - } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java index 153d4b35cca0..1377e15b0bb2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java @@ -22,6 +22,7 @@ import com.intellij.codeInspection.*; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase; import com.intellij.codeInspection.reference.*; import com.intellij.openapi.progress.EmptyProgressIndicator; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; import com.intellij.util.ObjectUtils; @@ -256,7 +257,7 @@ public class SameParameterValueInspectionBase extends GlobalJavaBatchInspectionT return manager.createProblemDescriptor(ObjectUtils.notNull(parameter.getNameIdentifier(), parameter), InspectionsBundle.message("inspection.same.parameter.problem.descriptor", "" + name + "", - "" + value + ""), + "" + StringUtil.unquoteString(value) + ""), createFix(name, value), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java index d6de5a38b1e9..071a8610b18a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java @@ -84,7 +84,7 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { myPackageLocalForMembersCheckbox = new JCheckBox(InspectionsBundle.message("inspection.visibility.option")); myPackageLocalForMembersCheckbox.setSelected(SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS); - myPackageLocalForMembersCheckbox.getModel().addChangeListener( + myPackageLocalForMembersCheckbox.getModel().addItemListener( e -> SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS = myPackageLocalForMembersCheckbox.isSelected()); gc.gridy = 0; @@ -92,7 +92,7 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { myPackageLocalForTopClassesCheckbox = new JCheckBox(InspectionsBundle.message("inspection.visibility.option1")); myPackageLocalForTopClassesCheckbox.setSelected(SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES); - myPackageLocalForTopClassesCheckbox.getModel().addChangeListener( + myPackageLocalForTopClassesCheckbox.getModel().addItemListener( e -> SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES = myPackageLocalForTopClassesCheckbox.isSelected()); gc.gridy = 1; @@ -101,7 +101,7 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { myPrivateForInnersCheckbox = new JCheckBox(InspectionsBundle.message("inspection.visibility.option2")); myPrivateForInnersCheckbox.setSelected(SUGGEST_PRIVATE_FOR_INNERS); - myPrivateForInnersCheckbox.getModel().addChangeListener(e -> SUGGEST_PRIVATE_FOR_INNERS = myPrivateForInnersCheckbox.isSelected()); + myPrivateForInnersCheckbox.getModel().addItemListener(e -> SUGGEST_PRIVATE_FOR_INNERS = myPrivateForInnersCheckbox.isSelected()); gc.gridy = 2; add(myPrivateForInnersCheckbox, gc); diff --git a/java/java-impl/src/com/intellij/codeInsight/JavaProjectCodeInsightSettings.java b/java/java-impl/src/com/intellij/codeInsight/JavaProjectCodeInsightSettings.java index 0ce294107be2..09ca840aa7e1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/JavaProjectCodeInsightSettings.java +++ b/java/java-impl/src/com/intellij/codeInsight/JavaProjectCodeInsightSettings.java @@ -84,7 +84,7 @@ public class JavaProjectCodeInsightSettings implements PersistentStateComponent< return excluded.length(); } - if (excluded.indexOf('*') > 0) { + if (excluded.indexOf('*') >= 0) { Matcher matcher = ourPatterns.get(excluded).matcher(name); if (matcher.lookingAt()) { return matcher.end(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java index 66133822c6a4..f0c07886e73d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java @@ -72,14 +72,21 @@ public class JavaCompletionSorting { sorter = sorter.weighAfter("priority", new PreferDefaultTypeWeigher(expectedTypes, parameters)); } + final PreferMostUsedWeigher preferMostUsedWeigher = PreferMostUsedWeigher.create(position); List afterStats = ContainerUtil.newArrayList(); afterStats.add(new PreferByKindWeigher(type, position, expectedTypes)); if (!smart) { - ContainerUtil.addIfNotNull(afterStats, preferStatics(position, expectedTypes)); + if (preferMostUsedWeigher == null) { + ContainerUtil.addIfNotNull(afterStats, preferStatics(position, expectedTypes)); + } if (!afterNew) { afterStats.add(new PreferExpected(false, expectedTypes, position)); } } + if (preferMostUsedWeigher != null) { + afterStats.add(preferMostUsedWeigher); + ContainerUtil.addIfNotNull(afterStats, preferStatics(position, expectedTypes)); + } ContainerUtil.addIfNotNull(afterStats, recursion(parameters, expectedTypes)); afterStats.add(new PreferSimilarlyEnding(expectedTypes)); if (ContainerUtil.or(expectedTypes, info -> !info.getType().equals(PsiType.VOID))) { @@ -88,10 +95,6 @@ public class JavaCompletionSorting { Collections.addAll(afterStats, new PreferAccessible(position), new PreferSimple()); sorter = sorter.weighAfter("stats", afterStats.toArray(new LookupElementWeigher[afterStats.size()])); - final PreferMostUsedWeigher preferMostUsedWeigher = PreferMostUsedWeigher.create(position); - if (preferMostUsedWeigher != null) { - sorter = sorter.weighAfter("stats", preferMostUsedWeigher); - } sorter = sorter.weighAfter("proximity", afterProximity.toArray(new LookupElementWeigher[afterProximity.size()])); return result.withRelevanceSorter(sorter); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaModuleCompletion.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaModuleCompletion.java index 1f22855ed2d5..f63dea163353 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaModuleCompletion.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaModuleCompletion.java @@ -30,8 +30,10 @@ import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Consumer; +import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; +import java.util.Set; import java.util.function.Predicate; import static com.intellij.codeInsight.completion.BasicExpressionCompletionContributor.createKeywordLookupItem; @@ -110,12 +112,18 @@ class JavaModuleCompletion { Project project = context.getProject(); JavaModuleNameIndex index = JavaModuleNameIndex.getInstance(); GlobalSearchScope scope = ProjectScope.getAllScope(project); + Set candidateNames = new THashSet<>(); index.processAllKeys(project, name -> { - if (!name.equals(hostName) && index.get(name, project, scope).size() == 1) { - result.consume(new OverrideableSpace(LookupElementBuilder.create(name), TailType.SEMICOLON)); + if (!name.equals(hostName)) { + candidateNames.add(name); } return true; }); + for(String candidateName:candidateNames) { + if(index.get(candidateName, project, scope).size() == 1) { + result.consume(new OverrideableSpace(LookupElementBuilder.create(candidateName), TailType.SEMICOLON)); + } + } } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferMostUsedWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferMostUsedWeigher.java index 5ec1c85d7756..afd2dd2abfb0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferMostUsedWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferMostUsedWeigher.java @@ -20,9 +20,8 @@ import com.intellij.codeInsight.lookup.LookupElementWeigher; import com.intellij.compiler.CompilerReferenceService; import com.intellij.patterns.PsiMethodPattern; import com.intellij.patterns.StandardPatterns; -import com.intellij.psi.CommonClassNames; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMember; +import com.intellij.psi.*; +import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,7 +29,7 @@ import org.jetbrains.annotations.Nullable; import static com.intellij.patterns.PsiJavaPatterns.psiMethod; class PreferMostUsedWeigher extends LookupElementWeigher { - static final PsiMethodPattern OBJECT_METHOD_PATTERN = psiMethod().withName( + private static final PsiMethodPattern OBJECT_METHOD_PATTERN = psiMethod().withName( StandardPatterns.string().oneOf("hashCode", "equals", "finalize", "wait", "notify", "notifyAll", "getClass", "clone", "toString")). inClass(CommonClassNames.JAVA_LANG_OBJECT); @@ -57,12 +56,40 @@ class PreferMostUsedWeigher extends LookupElementWeigher { if (!(psi instanceof PsiMember)) { return null; } - else { - if (OBJECT_METHOD_PATTERN.accepts(psi)) { - return null; - } - final Integer occurrenceCount = myCompilerReferenceService.getCompileTimeOccurrenceCount(psi, myConstructorSuggestion); - return occurrenceCount == null ? null : - occurrenceCount; + if (element.getUserData(JavaGenerateMemberCompletionContributor.GENERATE_ELEMENT) != null) { + return null; } + if (OBJECT_METHOD_PATTERN.accepts(psi)) { + return null; + } + if (looksLikeHelperMethodOrConst(psi)) { + return null; + } + final Integer occurrenceCount = myCompilerReferenceService.getCompileTimeOccurrenceCount(psi, myConstructorSuggestion); + return occurrenceCount == null ? null : -occurrenceCount; + } + + //Objects.requireNonNull is an example + private static boolean looksLikeHelperMethodOrConst(@NotNull PsiElement element) { + if (!(element instanceof PsiMethod)) return false; + PsiMethod method = (PsiMethod)element; + if (method.isConstructor()) return false; + if (isRawDeepTypeEqualToObject(method.getReturnType())) return true; + PsiParameter[] parameters = method.getParameterList().getParameters(); + if (parameters.length == 0) return false; + for (PsiParameter parameter : parameters) { + PsiType paramType = parameter.getType(); + if (isRawDeepTypeEqualToObject(paramType)) { + return true; + } + } + return false; + } + + private static boolean isRawDeepTypeEqualToObject(@Nullable PsiType type) { + if (type == null) return false; + PsiType rawType = TypeConversionUtil.erasure(type.getDeepComponentType()); + if (rawType == null) return false; + return rawType.equalsToText(CommonClassNames.JAVA_LANG_OBJECT); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java index 7da422c36c5a..4cc52be1aa29 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java @@ -462,7 +462,7 @@ public class MarkerType { return super.process(psiMethod); } }); - if (myMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { + if (ReadAction.compute(() -> myMethod.hasModifierProperty(PsiModifier.ABSTRACT))) { PsiClass psiClass = ReadAction.compute(myMethod::getContainingClass); FunctionalExpressionSearch.search(psiClass).forEach(new CommonProcessors.CollectProcessor() { @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java index 1285b99ebf95..f8bd27d96569 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -30,6 +30,7 @@ import com.intellij.ide.fileTemplates.FileTemplateUtil; import com.intellij.ide.fileTemplates.JavaTemplateUtil; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; @@ -45,7 +46,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; @@ -67,6 +67,7 @@ import com.intellij.psi.util.proximity.PsiProximityComparator; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -387,72 +388,68 @@ public class CreateFromUsageUtils { final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); final PsiElementFactory factory = facade.getElementFactory(); - return ApplicationManager.getApplication().runWriteAction( - new Computable() { - @Override - public PsiClass compute() { - try { - PsiClass targetClass; - if (directory != null) { - try { - if (classKind == CreateClassKind.INTERFACE) { - targetClass = JavaDirectoryService.getInstance().createInterface(directory, name); - } - else if (classKind == CreateClassKind.CLASS) { - targetClass = JavaDirectoryService.getInstance().createClass(directory, name); - } - else if (classKind == CreateClassKind.ENUM) { - targetClass = JavaDirectoryService.getInstance().createEnum(directory, name); - } - else if (classKind == CreateClassKind.ANNOTATION) { - targetClass = JavaDirectoryService.getInstance().createAnnotationType(directory, name); - } - else { - LOG.error("Unknown kind of a class to create"); - return null; - } - } - catch (final IncorrectOperationException e) { - scheduleFileOrPackageCreationFailedMessageBox(e, name, directory, false); - return null; - } - if (!facade.getResolveHelper().isAccessible(targetClass, contextElement, null)) { - PsiUtil.setModifierProperty(targetClass, PsiModifier.PUBLIC, true); - } - } - else { //tests - PsiClass aClass; + return WriteAction.compute(() -> { + try { + PsiClass targetClass; + if (directory != null) { + try { if (classKind == CreateClassKind.INTERFACE) { - aClass = factory.createInterface(name); + targetClass = JavaDirectoryService.getInstance().createInterface(directory, name); } else if (classKind == CreateClassKind.CLASS) { - aClass = factory.createClass(name); + targetClass = JavaDirectoryService.getInstance().createClass(directory, name); } else if (classKind == CreateClassKind.ENUM) { - aClass = factory.createEnum(name); + targetClass = JavaDirectoryService.getInstance().createEnum(directory, name); } else if (classKind == CreateClassKind.ANNOTATION) { - aClass = factory.createAnnotationType(name); + targetClass = JavaDirectoryService.getInstance().createAnnotationType(directory, name); } else { LOG.error("Unknown kind of a class to create"); return null; } - targetClass = (PsiClass) sourceFile.add(aClass); } + catch (final IncorrectOperationException e) { + scheduleFileOrPackageCreationFailedMessageBox(e, name, directory, false); + return null; + } + if (!facade.getResolveHelper().isAccessible(targetClass, contextElement, null)) { + PsiUtil.setModifierProperty(targetClass, PsiModifier.PUBLIC, true); + } + } + else { //tests + PsiClass aClass; + if (classKind == CreateClassKind.INTERFACE) { + aClass = factory.createInterface(name); + } + else if (classKind == CreateClassKind.CLASS) { + aClass = factory.createClass(name); + } + else if (classKind == CreateClassKind.ENUM) { + aClass = factory.createEnum(name); + } + else if (classKind == CreateClassKind.ANNOTATION) { + aClass = factory.createAnnotationType(name); + } + else { + LOG.error("Unknown kind of a class to create"); + return null; + } + targetClass = (PsiClass)sourceFile.add(aClass); + } - if (superClassName != null && (classKind != CreateClassKind.ENUM || !superClassName.equals(CommonClassNames.JAVA_LANG_ENUM))) { - setupSuperClassReference(targetClass, superClassName); - } - if (contextElement instanceof PsiJavaCodeReferenceElement) { - CreateFromUsageBaseFix.setupGenericParameters(targetClass, (PsiJavaCodeReferenceElement)contextElement); - } - return targetClass; + if (superClassName != null && (classKind != CreateClassKind.ENUM || !superClassName.equals(CommonClassNames.JAVA_LANG_ENUM))) { + setupSuperClassReference(targetClass, superClassName); } - catch (IncorrectOperationException e) { - LOG.error(e); - return null; + if (contextElement instanceof PsiJavaCodeReferenceElement) { + CreateFromUsageBaseFix.setupGenericParameters(targetClass, (PsiJavaCodeReferenceElement)contextElement); } + return targetClass; + } + catch (IncorrectOperationException e) { + LOG.error(e); + return null; } }); } @@ -571,16 +568,27 @@ public class CreateFromUsageUtils { List types, List expectedMethodNames, List expectedFieldNames) { + Comparator expectedTypesComparator = (o1, o2) -> compareExpectedTypes(o1, o2, expression); for (PsiExpression expr : collectExpressions(expression, PsiMember.class, PsiFile.class)) { PsiElement parent = expr.getParent(); if (!(parent instanceof PsiReferenceExpression)) { boolean isAssignmentToFunctionalExpression = PsiUtil.isOnAssignmentLeftHand(expr) && ((PsiAssignmentExpression)PsiUtil.skipParenthesizedExprUp(parent)).getRExpression() instanceof PsiFunctionalExpression; - boolean forCompletion = PsiUtil.skipParenthesizedExprUp(isAssignmentToFunctionalExpression ? parent.getParent() : parent) instanceof PsiExpressionList; + PsiExpressionList expressionList = ObjectUtils + .tryCast(PsiUtil.skipParenthesizedExprUp(isAssignmentToFunctionalExpression ? parent.getParent() : parent), + PsiExpressionList.class); + boolean forCompletion = expressionList != null; ExpectedTypeInfo[] someExpectedTypes = ExpectedTypesProvider.getExpectedTypes(expr, forCompletion); if (someExpectedTypes.length > 0) { - Arrays.sort(someExpectedTypes, (o1, o2) -> compareExpectedTypes(o1, o2, expression)); + Comparator comparator = expectedTypesComparator; + if (expressionList != null) { + int argCount = expressionList.getExpressions().length; + Comparator mostSuitableMethodComparator = + Comparator.comparingInt(typeInfo -> typeInfo.getCalledMethod().getParameterList().getParametersCount() == argCount ? 0 : 1); + comparator = mostSuitableMethodComparator.thenComparing(comparator); + } + Arrays.sort(someExpectedTypes, comparator); types.add(someExpectedTypes); } continue; @@ -597,7 +605,7 @@ public class CreateFromUsageUtils { if (refName.equals("equals")) { ExpectedTypeInfo[] someExpectedTypes = equalsExpectedTypes((PsiMethodCallExpression)pparent); if (someExpectedTypes.length > 0) { - Arrays.sort(someExpectedTypes, (o1, o2) -> compareExpectedTypes(o1, o2, expression)); + Arrays.sort(someExpectedTypes, expectedTypesComparator); types.add(someExpectedTypes); } } @@ -689,7 +697,7 @@ public class CreateFromUsageUtils { } - @Nullable + @NotNull static PsiType[] guessType(PsiExpression expression, final boolean allowVoidType) { final PsiManager manager = expression.getManager(); final GlobalSearchScope resolveScope = expression.getResolveScope(); @@ -876,12 +884,7 @@ public class CreateFromUsageUtils { final Module moduleForFile = ModuleUtilCore.findModuleForPsiElement(file); if (moduleForFile == null) return; - final GlobalSearchScope searchScope = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public GlobalSearchScope compute() { - return file.getResolveScope(); - } - }); + final GlobalSearchScope searchScope = ReadAction.compute(file::getResolveScope); GlobalSearchScope descendantsSearchScope = GlobalSearchScope.moduleWithDependenciesScope(moduleForFile); final JavaPsiFacade facade = JavaPsiFacade.getInstance(project); final PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project); @@ -890,12 +893,8 @@ public class CreateFromUsageUtils { return; } - final PsiMember[] members = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiMember[] compute() { - return method ? cache.getMethodsByName(memberName, searchScope) : cache.getFieldsByName(memberName, searchScope); - } - }); + final PsiMember[] members = ReadAction.compute( + () -> method ? cache.getMethodsByName(memberName, searchScope) : cache.getFieldsByName(memberName, searchScope)); for (int i = 0; i < members.length; ++i) { final PsiMember member = members[i]; @@ -921,7 +920,7 @@ public class CreateFromUsageUtils { private static boolean handleObjectMethod(Set possibleClassNames, final JavaPsiFacade facade, final GlobalSearchScope searchScope, final boolean method, final String memberName, final boolean staticAccess, boolean addInheritors) { final PsiShortNamesCache cache = PsiShortNamesCache.getInstance(facade.getProject()); final boolean[] allClasses = {false}; - ApplicationManager.getApplication().runReadAction(() -> { + ReadAction.run(() -> { final PsiClass objectClass = facade.findClass(CommonClassNames.JAVA_LANG_OBJECT, searchScope); if (objectClass != null) { if (method && objectClass.findMethodsByName(memberName, false).length > 0) { @@ -942,19 +941,9 @@ public class CreateFromUsageUtils { return true; } - final String[] strings = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String[] compute() { - return cache.getAllClassNames(); - } - }); + final String[] strings = ReadAction.compute(cache::getAllClassNames); for (final String className : strings) { - final PsiClass[] classes = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiClass[] compute() { - return cache.getClassesByName(className, searchScope); - } - }); + final PsiClass[] classes = ReadAction.compute(() -> cache.getClassesByName(className, searchScope)); for (final PsiClass aClass : classes) { final String qname = getQualifiedName(aClass); ContainerUtil.addIfNotNull(possibleClassNames, qname); @@ -967,13 +956,7 @@ public class CreateFromUsageUtils { @Nullable private static String getQualifiedName(final PsiClass aClass) { - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Nullable - @Override - public String compute() { - return aClass.getQualifiedName(); - } - }); + return ReadAction.compute(aClass::getQualifiedName); } private static boolean hasCorrectModifiers(@Nullable final PsiMember member, final boolean staticAccess) { @@ -981,12 +964,8 @@ public class CreateFromUsageUtils { return false; } - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - return !member.hasModifierProperty(PsiModifier.PRIVATE) && member.hasModifierProperty(PsiModifier.STATIC) == staticAccess; - } - }).booleanValue(); + return ReadAction.compute(() -> !member.hasModifierProperty(PsiModifier.PRIVATE) && + member.hasModifierProperty(PsiModifier.STATIC) == staticAccess).booleanValue(); } private static class ParameterNameExpression extends Expression { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/OrderEntryFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/OrderEntryFix.java index 13571b4dc8de..e41d9be7d87e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/OrderEntryFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/OrderEntryFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,6 +22,7 @@ import com.intellij.codeInsight.daemon.quickFix.ExternalLibraryResolver.External import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.DumbService; @@ -36,13 +37,15 @@ import com.intellij.psi.*; import com.intellij.psi.impl.source.PsiJavaModuleReference; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ThreeState; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UAnnotation; +import org.jetbrains.uast.UImportStatement; +import org.jetbrains.uast.UastContextKt; import java.io.File; import java.util.*; @@ -219,13 +222,13 @@ public abstract class OrderEntryFix implements IntentionAction, LocalQuickFix { } private static ThreeState isReferenceToAnnotation(final PsiElement psiElement) { - if (!PsiUtil.isLanguageLevel5OrHigher(psiElement)) { + if (psiElement.getLanguage() == JavaLanguage.INSTANCE && !PsiUtil.isLanguageLevel5OrHigher(psiElement)) { return ThreeState.NO; } - if (PsiTreeUtil.getParentOfType(psiElement, PsiAnnotation.class) != null) { + if (UastContextKt.getUastParentOfType(psiElement, UAnnotation.class) != null) { return ThreeState.YES; } - if (PsiTreeUtil.getParentOfType(psiElement, PsiImportStatement.class) != null) { + if (UastContextKt.getUastParentOfType(psiElement, UImportStatement.class) != null) { return ThreeState.UNSURE; } return ThreeState.NO; diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/DeclarationMover.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/DeclarationMover.java index 9f8e967b6640..80f2679fcfb6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/DeclarationMover.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/DeclarationMover.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,15 +20,20 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; +import com.intellij.openapi.util.Couple; 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.codeStyle.CodeStyleManager; import com.intellij.psi.impl.source.jsp.jspJava.JspClassLevelDeclarationStatement; import com.intellij.psi.impl.source.tree.Factory; import com.intellij.psi.impl.source.tree.TreeElement; +import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -147,8 +152,10 @@ class DeclarationMover extends LineMover { } Document document = editor.getDocument(); - PsiElement sibling = down ? range.lastElement.getNextSibling() : range.firstElement.getPrevSibling(); - sibling = firstNonWhiteElement(sibling, down); + PsiElement sibling = (down ? range.endLine >= document.getLineCount() : range.startLine == 0) ? null : + firstNonWhiteElement(down ? document.getLineStartOffset(range.endLine) + : document.getLineEndOffset(range.startLine - 1), + file, down); if (range.lastElement instanceof PsiEnumConstant && sibling instanceof PsiJavaToken) { final PsiJavaToken token = (PsiJavaToken)sibling; final IElementType tokenType = token.getTokenType(); @@ -163,35 +170,75 @@ class DeclarationMover extends LineMover { } final boolean areWeMovingClass = range.firstElement instanceof PsiClass; info.toMove = range; - try { - LineRange intraClassRange = moveInsideOutsideClassPosition(editor, sibling, down, areWeMovingClass); - if (intraClassRange == null) { - info.toMove2 = new LineRange(sibling, sibling, document); - if (down && sibling.getNextSibling() == null) return false; - } - else { - info.toMove2 = intraClassRange; - } - if (down ? info.toMove2.startLine < info.toMove.endLine : info.toMove2.endLine > info.toMove.startLine) { - return false; - } + + int neibourghLine = down ? range.endLine : range.startLine - 1; + if (neibourghLine >= 0 && neibourghLine < document.getLineCount() && + CharArrayUtil.containsOnlyWhiteSpaces(document.getImmutableCharSequence().subSequence(document.getLineStartOffset(neibourghLine), + document.getLineEndOffset(neibourghLine))) && + emptyLineCanBeDeletedAccordingToCodeStyle(file, document, document.getLineEndOffset(neibourghLine))) { + info.toMove2 = new LineRange(neibourghLine, neibourghLine + 1); } - catch (IllegalMoveException e) { - info.toMove2 = null; + else { + try { + LineRange intraClassRange = moveInsideOutsideClassPosition(editor, sibling, down, areWeMovingClass); + if (intraClassRange == null) { + Couple splitRange = extractCommentRange(sibling); + info.toMove2 = splitRange.first.startLine == splitRange.first.endLine || !down ? splitRange.second : splitRange.first; + if (down && sibling.getNextSibling() == null) return false; + } + else { + info.toMove2 = intraClassRange; + } + if (down ? info.toMove2.startLine < info.toMove.endLine : info.toMove2.endLine > info.toMove.startLine) { + return false; + } + } + catch (IllegalMoveException e) { + info.toMove2 = null; + } } return true; } + private static boolean emptyLineCanBeDeletedAccordingToCodeStyle(PsiFile file, Document document, int offset) { + CharSequence text = document.getImmutableCharSequence(); + String whitespace = " \t\n"; + int whitespaceStartOffset = CharArrayUtil.shiftBackward(text, offset - 1, whitespace) + 1; + int whitespaceEndOffset = CharArrayUtil.shiftForward(text, offset, whitespace); + int minLineFeeds = CodeStyleManager.getInstance(file.getProject()).getMinLineFeeds(file, whitespaceEndOffset); + int actualLineFeeds = StringUtil.countNewLines(text.subSequence(whitespaceStartOffset, whitespaceEndOffset)); + return actualLineFeeds > minLineFeeds; + } + private static LineRange memberRange(@NotNull PsiElement member, Editor editor, LineRange lineRange) { final TextRange textRange = member.getTextRange(); if (editor.getDocument().getTextLength() < textRange.getEndOffset()) return null; - final int startLine = editor.offsetToLogicalPosition(textRange.getStartOffset()).line; - final int endLine = editor.offsetToLogicalPosition(textRange.getEndOffset()).line+1; + int startLine = editor.offsetToLogicalPosition(textRange.getStartOffset()).line; + int endLine = editor.offsetToLogicalPosition(textRange.getEndOffset()).line+1; + + // if member includes a comment (non-javadoc) and it wasn't selected by user, don't move it with member + Couple splitRanges = extractCommentRange(member); + if (lineRange.startLine >= splitRanges.first.endLine) startLine = splitRanges.second.startLine; + else if (lineRange.endLine < splitRanges.second.startLine) endLine = splitRanges.first.endLine; + if (!isInsideDeclaration(member, startLine, endLine, lineRange, editor)) return null; return new LineRange(startLine, endLine); } + + private static Couple extractCommentRange(@NotNull PsiElement member) { + PsiElement firstChild = member.getFirstChild(); + if (firstChild instanceof PsiComment && !(firstChild instanceof PsiDocComment)) { + PsiElement nextElement = firstNonWhiteElement(firstChild.getNextSibling(), true); + if (nextElement != null) { + return Couple.of(new LineRange(firstChild), new LineRange(nextElement, member)); + } + } + LineRange wholeRange = new LineRange(member); + return Couple.of(new LineRange(wholeRange.startLine, wholeRange.startLine), wholeRange); + } + private static boolean isInsideDeclaration(@NotNull final PsiElement member, final int startLine, final int endLine, diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementsAnnotationsHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementsAnnotationsHandler.java index 497d84d23014..e41d252a4883 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementsAnnotationsHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementsAnnotationsHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -13,11 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * User: anna - * Date: 19-Aug-2008 - */ package com.intellij.codeInsight.generation; import com.intellij.codeInsight.AnnotationUtil; @@ -33,6 +28,10 @@ import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** + * @author anna + * @since 19-Aug-2008 + */ public interface OverrideImplementsAnnotationsHandler { ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.overrideImplementsAnnotationsHandler"); @@ -45,6 +44,7 @@ public interface OverrideImplementsAnnotationsHandler { @Deprecated @NotNull + @SuppressWarnings("unused") default String [] annotationsToRemove(Project project, @NotNull String fqName) { return ArrayUtil.EMPTY_STRING_ARRAY; } @@ -57,9 +57,9 @@ public interface OverrideImplementsAnnotationsHandler { for (OverrideImplementsAnnotationsHandler each : Extensions.getExtensions(EP_NAME)) { for (String annotation : each.getAnnotations(project)) { if (moduleScope != null && facade.findClass(annotation, moduleScope) == null) continue; + if (AnnotationUtil.isAnnotated(source, annotation, false, false) && !AnnotationUtil.isAnnotated(target, annotation, false, false)) { - PsiAnnotation psiAnnotation = AnnotationUtil.findAnnotation(source, annotation); if (psiAnnotation != null && AnnotationUtil.isInferredAnnotation(psiAnnotation)) { continue; diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementsAnnotationsHandlerImpl.java b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementsAnnotationsHandlerImpl.java index 848cabda2b69..7cad3feceda2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementsAnnotationsHandlerImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementsAnnotationsHandlerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,17 +28,22 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.util.ArrayUtil; import java.util.ArrayList; -import java.util.Collection; +import java.util.List; public class OverrideImplementsAnnotationsHandlerImpl implements OverrideImplementsAnnotationsHandler { @Override public String[] getAnnotations(Project project) { - final NullableNotNullManager manager = NullableNotNullManager.getInstance(project); - final Collection anns = new ArrayList<>(manager.getNotNulls()); - anns.addAll(manager.getNullables()); - anns.add(AnnotationUtil.NLS); - final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(project); - anns.addAll(settings.getRepeatAnnotations()); - return ArrayUtil.toStringArray(anns); + List annotations = new ArrayList<>(); + + NullableNotNullManager manager = NullableNotNullManager.getInstance(project); + annotations.addAll(manager.getNotNulls()); + annotations.addAll(manager.getNullables()); + + annotations.add(AnnotationUtil.NLS); + + CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(project); + annotations.addAll(settings.getRepeatAnnotations()); + + return ArrayUtil.toStringArray(annotations); } -} +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java index 8a102e458e5a..f0f90b1c88b2 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java @@ -25,8 +25,6 @@ import com.intellij.util.ui.JBUI; import com.siyeh.ig.fixes.IntroduceVariableFix; import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import java.awt.*; import java.util.List; @@ -90,76 +88,39 @@ public class DataFlowInspection extends DataFlowInspectionBase { mySuggestNullables = new JCheckBox( InspectionsBundle.message("inspection.data.flow.nullable.quickfix.option")); mySuggestNullables.setSelected(SUGGEST_NULLABLE_ANNOTATIONS); - mySuggestNullables.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - SUGGEST_NULLABLE_ANNOTATIONS = mySuggestNullables.isSelected(); - } - }); + mySuggestNullables.getModel().addItemListener(e -> SUGGEST_NULLABLE_ANNOTATIONS = mySuggestNullables.isSelected()); myDontReportTrueAsserts = new JCheckBox( InspectionsBundle.message("inspection.data.flow.true.asserts.option")); myDontReportTrueAsserts.setSelected(DONT_REPORT_TRUE_ASSERT_STATEMENTS); - myDontReportTrueAsserts.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - DONT_REPORT_TRUE_ASSERT_STATEMENTS = myDontReportTrueAsserts.isSelected(); - } - }); + myDontReportTrueAsserts.getModel().addItemListener(e -> DONT_REPORT_TRUE_ASSERT_STATEMENTS = myDontReportTrueAsserts.isSelected()); myIgnoreAssertions = new JCheckBox("Ignore assert statements"); myIgnoreAssertions.setSelected(IGNORE_ASSERT_STATEMENTS); - myIgnoreAssertions.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - IGNORE_ASSERT_STATEMENTS = myIgnoreAssertions.isSelected(); - } - }); + myIgnoreAssertions.getModel().addItemListener(e -> IGNORE_ASSERT_STATEMENTS = myIgnoreAssertions.isSelected()); myReportConstantReferences = new JCheckBox("Warn when reading a value guaranteed to be constant"); myReportConstantReferences.setSelected(REPORT_CONSTANT_REFERENCE_VALUES); - myReportConstantReferences.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - REPORT_CONSTANT_REFERENCE_VALUES = myReportConstantReferences.isSelected(); - } - }); + myReportConstantReferences.getModel().addItemListener( + e -> REPORT_CONSTANT_REFERENCE_VALUES = myReportConstantReferences.isSelected()); myTreatUnknownMembersAsNullable = new JCheckBox("Treat non-annotated members and parameters as @Nullable"); myTreatUnknownMembersAsNullable.setSelected(TREAT_UNKNOWN_MEMBERS_AS_NULLABLE); - myTreatUnknownMembersAsNullable.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - TREAT_UNKNOWN_MEMBERS_AS_NULLABLE = myTreatUnknownMembersAsNullable.isSelected(); - } - }); + myTreatUnknownMembersAsNullable.getModel().addItemListener( + e -> TREAT_UNKNOWN_MEMBERS_AS_NULLABLE = myTreatUnknownMembersAsNullable.isSelected()); myReportNullArguments = new JCheckBox("Report not-null required parameter with null-literal argument usages"); myReportNullArguments.setSelected(REPORT_NULLS_PASSED_TO_NOT_NULL_PARAMETER); - myReportNullArguments.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - REPORT_NULLS_PASSED_TO_NOT_NULL_PARAMETER = myReportNullArguments.isSelected(); - } - }); + myReportNullArguments.getModel().addItemListener(e -> REPORT_NULLS_PASSED_TO_NOT_NULL_PARAMETER = myReportNullArguments.isSelected()); myReportNullableMethodsReturningNotNull = new JCheckBox("Report nullable methods that always return a non-null value"); myReportNullableMethodsReturningNotNull.setSelected(REPORT_NULLABLE_METHODS_RETURNING_NOT_NULL); - myReportNullableMethodsReturningNotNull.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - REPORT_NULLABLE_METHODS_RETURNING_NOT_NULL = myReportNullableMethodsReturningNotNull.isSelected(); - } - }); + myReportNullableMethodsReturningNotNull.getModel().addItemListener( + e -> REPORT_NULLABLE_METHODS_RETURNING_NOT_NULL = myReportNullableMethodsReturningNotNull.isSelected()); myReportUncheckedOptionals = new JCheckBox("Report Optional.get() calls without previous isPresent check"); myReportUncheckedOptionals.setSelected(REPORT_UNCHECKED_OPTIONALS); - myReportUncheckedOptionals.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - REPORT_UNCHECKED_OPTIONALS = myReportUncheckedOptionals.isSelected(); - } - }); + myReportUncheckedOptionals.getModel().addItemListener(e -> REPORT_UNCHECKED_OPTIONALS = myReportUncheckedOptionals.isSelected()); gc.insets = JBUI.emptyInsets(); gc.gridy = 0; diff --git a/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaReflectionInvocationInspection.java b/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaReflectionInvocationInspection.java index abd323f67c33..6d210a11311e 100644 --- a/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaReflectionInvocationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaReflectionInvocationInspection.java @@ -115,7 +115,8 @@ public class JavaReflectionInvocationInspection extends BaseJavaBatchLocalInspec final PsiExpression[] expressions = argumentList.getExpressions(); final PsiElement element = expressions.length == argumentOffset + 1 ? expressions[argumentOffset] : argumentList; holder.registerProblem(element, InspectionsBundle.message( - "inspection.reflection.invocation.item.number.not.assignable", i, requiredType.getQualifiedName())); + "inspection.reflection.invocation.array.not.assignable", actualArguments.expressions.length)); + break; } } } diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java index 01d40e0e3f5b..e012812e3cf8 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java @@ -21,7 +21,9 @@ import com.intellij.codeInspection.*; import com.intellij.codeInspection.reference.*; import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.openapi.util.WriteExternalException; -import com.intellij.psi.*; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiReference; import com.intellij.psi.util.PropertyUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -55,6 +57,7 @@ public class UnusedReturnValue extends GlobalJavaBatchInspectionTool{ final boolean isNative = psiMethod.hasModifierProperty(PsiModifier.NATIVE); if (refMethod.isExternalOverride() && !isNative) return null; + if (RefUtil.isImplicitRead(psiMethod)) return null; return new ProblemDescriptor[]{createProblemDescriptor(psiMethod, manager, processor, isNative)}; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValueLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValueLocalInspection.java index 850e45c9db92..decd81176a26 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValueLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValueLocalInspection.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.daemon.impl.UnusedSymbolUtil; import com.intellij.codeInspection.BaseJavaLocalInspectionTool; import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.reference.RefUtil; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; @@ -57,7 +58,8 @@ public class UnusedReturnValueLocalInspection extends BaseJavaLocalInspectionToo PsiType.VOID.equals(method.getReturnType()) || myGlobal.IGNORE_BUILDER_PATTERN && PropertyUtil.isSimplePropertySetter(method) || method.hasModifierProperty(PsiModifier.NATIVE) || - MethodUtils.hasSuper(method)) return null; + MethodUtils.hasSuper(method) || + RefUtil.isImplicitRead(method)) return null; final boolean[] atLeastOneUsageExists = new boolean[]{false}; if (UnusedSymbolUtil.processUsages(manager.getProject(), method.getContainingFile(), method, new EmptyProgressIndicator(), null, u -> { diff --git a/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java b/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java index 631b02079716..7e67d189bf20 100644 --- a/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java +++ b/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java @@ -154,6 +154,7 @@ public class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSett "CATCH_ON_NEW_LINE", "FINALLY_ON_NEW_LINE", "INDENT_CASE_FROM_SWITCH", + "CASE_STATEMENT_ON_NEW_LINE", "SPECIAL_ELSE_IF_TREATMENT", "ENUM_CONSTANTS_WRAP", "ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS", diff --git a/java/java-impl/src/com/intellij/ide/actions/CreateModuleInfoAction.java b/java/java-impl/src/com/intellij/ide/actions/CreateModuleInfoAction.java index e7574102d223..208b4895697f 100644 --- a/java/java-impl/src/com/intellij/ide/actions/CreateModuleInfoAction.java +++ b/java/java-impl/src/com/intellij/ide/actions/CreateModuleInfoAction.java @@ -61,7 +61,7 @@ public class CreateModuleInfoAction extends CreateFromTemplateActionBase { .map(view -> getTargetDirectory(ctx, view)) .filter(PsiUtil::isLanguageLevel9OrHigher) .map(ModuleUtilCore::findModuleForPsiElement) - .map(module -> FilenameIndex.getVirtualFilesByName(module.getProject(), MODULE_INFO_FILE, module.getModuleScope(false)).isEmpty()) + .map(module -> FilenameIndex.getVirtualFilesByName(module.getProject(), MODULE_INFO_FILE, module.getModuleScope()).isEmpty()) .orElse(false); e.getPresentation().setEnabledAndVisible(available); } diff --git a/java/java-impl/src/com/intellij/jarRepository/services/nexus/NexusRepositoryService.java b/java/java-impl/src/com/intellij/jarRepository/services/nexus/NexusRepositoryService.java index 2eb0f2c9bea1..10a7a785f619 100644 --- a/java/java-impl/src/com/intellij/jarRepository/services/nexus/NexusRepositoryService.java +++ b/java/java-impl/src/com/intellij/jarRepository/services/nexus/NexusRepositoryService.java @@ -98,7 +98,7 @@ public class NexusRepositoryService extends MavenRepositoryService { final SearchResults results = new Endpoint.DataIndex(url).getArtifactlistAsSearchResults( name, template.getGroupId(), template.getArtifactId(), template.getVersion(), null, template.getClassNames() ); - boolean tooManyResults = results.isTooManyResults(); + //boolean tooManyResults = results.isTooManyResults(); final SearchResults.Data data = results.getData(); final ArrayList result = new ArrayList<>(); if (data != null) { @@ -108,9 +108,9 @@ public class NexusRepositoryService extends MavenRepositoryService { } } } - if (tooManyResults) { - result.add(null); - } + //if (tooManyResults) { + // result.add(null); + //} return result; } catch (UnmarshalException e) { diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocGeneratorRunProfile.java b/java/java-impl/src/com/intellij/javadoc/JavadocGeneratorRunProfile.java index cfff53105259..f36fe20cca2f 100644 --- a/java/java-impl/src/com/intellij/javadoc/JavadocGeneratorRunProfile.java +++ b/java/java-impl/src/com/intellij/javadoc/JavadocGeneratorRunProfile.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -91,11 +91,6 @@ public class JavadocGeneratorRunProfile implements ModuleRunProfile { return null; } - @NotNull - public Module[] getModules() { - return Module.EMPTY_ARRAY; - } - private static class MyJavaCommandLineState extends CommandLineState { private final AnalysisScope myGenerationOptions; private final Project myProject; diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java index 45d84b017760..62e2c3def786 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java @@ -869,10 +869,14 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { myResult = Spacing.createDependentLFSpacing(0, 1, textRange, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE); } } - else if (myChild1.getElementType() == JavaElementType.SWITCH_LABEL_STATEMENT - && myChild2.getElementType() == JavaElementType.BLOCK_STATEMENT) - { - myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_SWITCH_LBRACE, null); + else if (myChild1.getElementType() == JavaElementType.SWITCH_LABEL_STATEMENT) { + if (myChild2.getElementType() == JavaElementType.BLOCK_STATEMENT) { + myResult = getSpaceBeforeLBrace(myChild2, mySettings.SPACE_BEFORE_SWITCH_LBRACE, null); + } + else { + int lineFeeds = mySettings.CASE_STATEMENT_ON_NEW_LINE ? 1 : 0; + myResult = Spacing.createSpacing(1, 1, lineFeeds, true, mySettings.KEEP_BLANK_LINES_IN_CODE); + } } else if (lhsStatement && rhsStatement) { int minSpaces = 0; diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceUtil.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceUtil.java index 1328cb519c9c..670c5eae7d60 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceUtil.java @@ -374,12 +374,15 @@ public class JavaReflectionReferenceUtil { if (type.equals(PsiType.NULL)) { return myPsiClass != null || myArrayDimensions != 0; } - if (type.getArrayDimensions() != myArrayDimensions) { - return false; + PsiType otherType = type; + for (int i = 0; i < myArrayDimensions; i++) { + if (!(otherType instanceof PsiArrayType)) { + return false; + } + otherType = ((PsiArrayType)otherType).getComponentType(); } - final PsiType otherType = type.getDeepComponentType(); if (myPrimitiveType != null) { - return myPrimitiveType.isAssignableFrom(otherType) || otherType.equalsToText(myPrimitiveType.getBoxedTypeName()); + return myPrimitiveType.isAssignableFrom(otherType); } final PsiElementFactory factory = JavaPsiFacade.getInstance(myPsiClass.getProject()).getElementFactory(); return factory.createType(myPsiClass).isAssignableFrom(otherType); diff --git a/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodDialog.java b/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodDialog.java index 9d4c19394ae3..911b946bdfa5 100644 --- a/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodDialog.java @@ -19,7 +19,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.help.HelpManager; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiParameter; -import com.intellij.psi.PsiVariable; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.move.moveInstanceMethod.MoveInstanceMethodDialogBase; @@ -35,16 +34,16 @@ import java.awt.event.MouseEvent; */ public class ConvertToInstanceMethodDialog extends MoveInstanceMethodDialogBase { private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.convertToInstanceMethod.ConvertToInstanceMethodDialog"); - public ConvertToInstanceMethodDialog(final PsiMethod method, final PsiParameter[] variables) { + public ConvertToInstanceMethodDialog(final PsiMethod method, final Object[] variables) { super(method, variables, ConvertToInstanceMethodHandler.REFACTORING_NAME); init(); } protected void doAction() { - final PsiVariable targetVariable = (PsiVariable)myList.getSelectedValue(); - LOG.assertTrue(targetVariable instanceof PsiParameter, targetVariable); + final Object targetVariable = myList.getSelectedValue(); + LOG.assertTrue(targetVariable != null); final ConvertToInstanceMethodProcessor processor = new ConvertToInstanceMethodProcessor(myMethod.getProject(), - myMethod, (PsiParameter)targetVariable, + myMethod, targetVariable instanceof PsiParameter ? (PsiParameter)targetVariable : null, myVisibilityPanel.getVisibility()); if (!verifyTargetClass(processor.getTargetClass())) return; invokeRefactoring(processor); diff --git a/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodHandler.java b/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodHandler.java index 90ad06ce5ed5..9d045fcd3c17 100644 --- a/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodHandler.java @@ -17,8 +17,6 @@ package com.intellij.refactoring.convertToInstanceMethod; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.LangDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; @@ -28,9 +26,11 @@ import com.intellij.refactoring.HelpID; import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.util.CommonRefactoringUtil; +import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -71,44 +71,28 @@ public class ConvertToInstanceMethodHandler implements RefactoringActionHandler return; } final PsiParameter[] parameters = method.getParameterList().getParameters(); - List suitableParameters = new ArrayList<>(); - boolean classTypesFound = false; - boolean resolvableClassesFound = false; - boolean classesInProjectFound = false; + List targetQualifiers = new ArrayList<>(); for (final PsiParameter parameter : parameters) { final PsiType type = parameter.getType(); if (type instanceof PsiClassType) { - classTypesFound = true; final PsiClass psiClass = ((PsiClassType)type).resolve(); if (psiClass != null && !(psiClass instanceof PsiTypeParameter)) { - resolvableClassesFound = true; - final boolean inProject = method.getManager().isInProject(psiClass); - if (inProject) { - classesInProjectFound = true; - suitableParameters.add(parameter); + if (method.getManager().isInProject(psiClass)) { + targetQualifiers.add(parameter); } } } } - if (suitableParameters.isEmpty()) { - String message = null; - if (!classTypesFound) { - message = RefactoringBundle.message("convertToInstanceMethod.no.parameters.with.reference.type"); - } - else if (!resolvableClassesFound) { - message = RefactoringBundle.message("convertToInstanceMethod.all.reference.type.parametres.have.unknown.types"); - } - else if (!classesInProjectFound) { - message = RefactoringBundle.message("convertToInstanceMethod.all.reference.type.parameters.are.not.in.project"); - } - LOG.assertTrue(message != null); - Editor editor = CommonDataKeys.EDITOR.getData(dataContext); - CommonRefactoringUtil.showErrorHint(project, editor, RefactoringBundle.getCannotRefactorMessage(message), REFACTORING_NAME, HelpID.CONVERT_TO_INSTANCE_METHOD); - return; + PsiClass containingClass = method.getContainingClass(); + if (containingClass == null || containingClass.getQualifiedName() == null) return; + String className = containingClass.getName(); + PsiMethod[] constructors = containingClass.getConstructors(); + boolean noArgConstructor = + constructors.length == 0 || Arrays.stream(constructors).anyMatch(constructor -> constructor.getParameterList().getParametersCount() == 0); + if (noArgConstructor) { + targetQualifiers.add("this / new " + className + "()"); } - new ConvertToInstanceMethodDialog( - method, - suitableParameters.toArray(new PsiParameter[suitableParameters.size()])).show(); + new ConvertToInstanceMethodDialog(method, ArrayUtil.toObjectArray(targetQualifiers)).show(); } } diff --git a/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodProcessor.java index ed422af0250f..f84e740e4f43 100644 --- a/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodProcessor.java @@ -29,6 +29,7 @@ import com.intellij.psi.javadoc.PsiDocTagValue; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.BaseRefactoringProcessor; @@ -54,7 +55,7 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.convertToInstanceMethod.ConvertToInstanceMethodProcessor"); private PsiMethod myMethod; - private PsiParameter myTargetParameter; + private @Nullable PsiParameter myTargetParameter; private PsiClass myTargetClass; private Map myTypeParameterReplacements; private static final Key BIND_TO_TYPE_PARAMETER = Key.create("REPLACEMENT"); @@ -64,17 +65,22 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { public ConvertToInstanceMethodProcessor(final Project project, final PsiMethod method, - final PsiParameter targetParameter, + @Nullable final PsiParameter targetParameter, final String newVisibility) { super(project); myMethod = method; myTargetParameter = targetParameter; LOG.assertTrue(method.hasModifierProperty(PsiModifier.STATIC)); - LOG.assertTrue(myTargetParameter.getDeclarationScope() == myMethod); - LOG.assertTrue(myTargetParameter.getType() instanceof PsiClassType); - final PsiType type = myTargetParameter.getType(); - LOG.assertTrue(type instanceof PsiClassType); - myTargetClass = ((PsiClassType)type).resolve(); + if (myTargetParameter != null) { + LOG.assertTrue(myTargetParameter.getDeclarationScope() == myMethod); + LOG.assertTrue(myTargetParameter.getType() instanceof PsiClassType); + final PsiType type = myTargetParameter.getType(); + LOG.assertTrue(type instanceof PsiClassType); + myTargetClass = ((PsiClassType)type).resolve(); + } + else { + myTargetClass = method.getContainingClass(); + } myOldVisibility = VisibilityUtil.getVisibilityModifier(method.getModifierList()); myNewVisibility = newVisibility; } @@ -89,15 +95,15 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { } protected void refreshElements(@NotNull PsiElement[] elements) { - LOG.assertTrue(elements.length == 3); + LOG.assertTrue(elements.length > 1); myMethod = (PsiMethod)elements[0]; - myTargetParameter = (PsiParameter)elements[1]; - myTargetClass = (PsiClass)elements[2]; + myTargetParameter = elements.length == 3 ? (PsiParameter)elements[1] : null; + myTargetClass = (PsiClass)elements[elements.length - 1]; } @NotNull protected UsageInfo[] findUsages() { - LOG.assertTrue(myTargetParameter.getDeclarationScope() == myMethod); + LOG.assertTrue(myTargetParameter == null || myTargetParameter.getDeclarationScope() == myMethod); final Project project = myMethod.getProject(); final PsiReference[] methodReferences = @@ -106,8 +112,12 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { for (final PsiReference ref : methodReferences) { final PsiElement element = ref.getElement(); if (element instanceof PsiReferenceExpression) { - if (element.getParent() instanceof PsiMethodCallExpression) { - result.add(new MethodCallUsageInfo((PsiMethodCallExpression)element.getParent())); + PsiElement parent = element.getParent(); + if (parent instanceof PsiMethodCallExpression) { + result.add(new MethodCallUsageInfo((PsiMethodCallExpression)parent)); + } + else if (element instanceof PsiMethodReferenceExpression) { + result.add(new MethodReferenceUsageInfo((PsiMethodReferenceExpression)element, myTargetParameter == null || myMethod.getParameterList().getParameterIndex(myTargetParameter) == 0)); } } else if (element instanceof PsiDocTagValue) { @@ -115,10 +125,12 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { } } - for (final PsiReference ref : ReferencesSearch.search(myTargetParameter, new LocalSearchScope(myMethod), false)) { - final PsiElement element = ref.getElement(); - if (element instanceof PsiReferenceExpression || element instanceof PsiDocParamRef) { - result.add(new ParameterUsageInfo(ref)); + if (myTargetParameter != null) { + for (final PsiReference ref : ReferencesSearch.search(myTargetParameter, new LocalSearchScope(myMethod), false)) { + final PsiElement element = ref.getElement(); + if (element instanceof PsiReferenceExpression || element instanceof PsiDocParamRef) { + result.add(new ParameterUsageInfo(ref)); + } } } @@ -173,21 +185,34 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { } for (final UsageInfo usageInfo : usagesIn) { + PsiElement place = null; if (usageInfo instanceof MethodCallUsageInfo) { - final PsiMethodCallExpression methodCall = ((MethodCallUsageInfo)usageInfo).getMethodCall(); - final PsiExpression[] expressions = methodCall.getArgumentList().getExpressions(); - final int index = myMethod.getParameterList().getParameterIndex(myTargetParameter); - if (index < expressions.length) { - PsiExpression instanceValue = expressions[index]; - instanceValue = RefactoringUtil.unparenthesizeExpression(instanceValue); - if (instanceValue instanceof PsiLiteralExpression && ((PsiLiteralExpression)instanceValue).getValue() == null) { - String message = RefactoringBundle.message("0.contains.call.with.null.argument.for.parameter.1", - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(methodCall), true), - CommonRefactoringUtil.htmlEmphasize(myTargetParameter.getName())); - conflicts.putValue(methodCall, message); + place = ((MethodCallUsageInfo)usageInfo).getMethodCall(); + if (myTargetParameter != null) { + final PsiExpression[] expressions = ((PsiMethodCallExpression)place).getArgumentList().getExpressions(); + final int index = myMethod.getParameterList().getParameterIndex(myTargetParameter); + if (index < expressions.length) { + PsiExpression instanceValue = expressions[index]; + instanceValue = RefactoringUtil.unparenthesizeExpression(instanceValue); + if (instanceValue instanceof PsiLiteralExpression && ((PsiLiteralExpression)instanceValue).getValue() == null) { + String message = RefactoringBundle.message("0.contains.call.with.null.argument.for.parameter.1", + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(place), true), + CommonRefactoringUtil.htmlEmphasize(myTargetParameter.getName())); + conflicts.putValue(place, message); + } } } } + else if (usageInfo instanceof MethodReferenceUsageInfo) { + place = ((MethodReferenceUsageInfo)usageInfo).getExpression(); + if (!((MethodReferenceUsageInfo)usageInfo).isApplicableBySecondSearch()) { + conflicts.putValue(place, RefactoringBundle.message("expand.method.reference.warning")); + } + } + + if (myTargetParameter == null && place != null && myTargetClass.hasTypeParameters() && !thisAccessExpressionApplicable(place)) { + conflicts.putValue(place, "Impossible to infer class type arguments. When proceed, raw " + myTargetClass.getName() + " would be created"); + } } return showConflicts(conflicts, usagesIn); @@ -216,7 +241,7 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { // Process usages for (final UsageInfo usage : usages) { if (usage instanceof MethodCallUsageInfo) { - processMethodCall((MethodCallUsageInfo)usage); + processMethodCall(((MethodCallUsageInfo)usage).getMethodCall()); } else if (usage instanceof ParameterUsageInfo) { processParameterUsage((ParameterUsageInfo)usage); @@ -224,10 +249,13 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { else if (usage instanceof ImplementingClassUsageInfo) { inheritors.add(((ImplementingClassUsageInfo)usage).getPsiClass()); } + else if (usage instanceof MethodReferenceUsageInfo) { + processMethodReference((MethodReferenceUsageInfo)usage); + } } prepareTypeParameterReplacement(); - myTargetParameter.delete(); + if (myTargetParameter != null) myTargetParameter.delete(); ChangeContextUtil.encodeContextInfo(myMethod, true); if (!myTargetClass.isInterface()) { PsiMethod method = addMethodToClass(myTargetClass); @@ -256,15 +284,54 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { myMethod.delete(); } + private void processMethodReference(MethodReferenceUsageInfo usage) { + PsiMethodReferenceExpression expression = usage.getExpression(); + if (usage.isApplicableBySecondSearch()) { + PsiExpression qualifierExpression = expression.getQualifierExpression(); + LOG.assertTrue(qualifierExpression != null); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(myProject); + PsiElement qualifier; + if (myTargetParameter != null) { + qualifier = factory.createReferenceExpression(myTargetClass); + } + else { + boolean thisAccess = thisAccessExpressionApplicable(expression); + qualifier = thisAccess + ? factory.createExpressionFromText("this", qualifierExpression) + : createSyntheticAccessExpression(factory, expression); + } + qualifierExpression.replace(qualifier); + } + else { + PsiLambdaExpression lambdaExpression = LambdaRefactoringUtil.convertMethodReferenceToLambda(expression, false, true); + List returnExpressions = LambdaUtil.getReturnExpressions(lambdaExpression); + if (!returnExpressions.isEmpty()) { + PsiMethodCallExpression methodCall = (PsiMethodCallExpression)returnExpressions.get(0); + processMethodCall(methodCall); + usage.setReplacement(methodCall); + } + } + } + private void fixVisibility(final PsiMethod method, final UsageInfo[] usages) throws IncorrectOperationException { final PsiModifierList modifierList = method.getModifierList(); if (VisibilityUtil.ESCALATE_VISIBILITY.equals(myNewVisibility)) { for (UsageInfo usage : usages) { + PsiElement place = null; if (usage instanceof MethodCallUsageInfo) { - final PsiElement place = usage.getElement(); - if (place != null) { - VisibilityUtil.escalateVisibility(method, place); + place = usage.getElement(); + } + else if (usage instanceof MethodReferenceUsageInfo) { + PsiMethodReferenceExpression expression = ((MethodReferenceUsageInfo)usage).getExpression(); + if (expression != null && expression.isValid()) { + place = expression; } + else { + place = ((MethodReferenceUsageInfo)usage).getReplacement(); + } + } + if (place != null) { + VisibilityUtil.escalateVisibility(method, place); } } } @@ -354,6 +421,7 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { } private static boolean sameUnqualified(PsiElement parent) { + if (parent instanceof PsiMethodReferenceExpression) return false; PsiElement resolve = ((PsiReferenceExpression)parent).resolve(); if (resolve instanceof PsiField) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(resolve.getProject()); @@ -363,14 +431,29 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { return true; } - private void processMethodCall(MethodCallUsageInfo usageInfo) throws IncorrectOperationException { - PsiMethodCallExpression methodCall = usageInfo.getMethodCall(); - PsiParameterList parameterList = myMethod.getParameterList(); + private void processMethodCall(final PsiMethodCallExpression methodCall) throws IncorrectOperationException { PsiElementFactory factory = JavaPsiFacade.getInstance(myMethod.getProject()).getElementFactory(); - int parameterIndex = parameterList.getParameterIndex(myTargetParameter); - PsiExpression[] arguments = methodCall.getArgumentList().getExpressions(); - if (arguments.length <= parameterIndex) return; final PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); + PsiExpression argument; + if (myTargetParameter != null) { + PsiParameterList parameterList = myMethod.getParameterList(); + int parameterIndex = parameterList.getParameterIndex(myTargetParameter); + PsiExpression[] arguments = methodCall.getArgumentList().getExpressions(); + if (arguments.length <= parameterIndex) return; + argument = arguments[parameterIndex]; + } + else { + if (thisAccessExpressionApplicable(methodCall)) { + PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); + if (qualifierExpression != null) { + qualifierExpression.delete(); + } + return; + } + + argument = createSyntheticAccessExpression(factory, methodCall); + } + final PsiExpression qualifier; if (methodExpression.getQualifierExpression() != null) { qualifier = methodExpression.getQualifierExpression(); @@ -379,16 +462,29 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { final PsiReferenceExpression newRefExpr = (PsiReferenceExpression)factory.createExpressionFromText("x." + myMethod.getName(), null); qualifier = ((PsiReferenceExpression)methodExpression.replace(newRefExpr)).getQualifierExpression(); } - qualifier.replace(arguments[parameterIndex]); - arguments[parameterIndex].delete(); + qualifier.replace(argument); + argument.delete(); } + private PsiExpression createSyntheticAccessExpression(PsiElementFactory factory, PsiElement context) { + return factory.createExpressionFromText("new " + myTargetClass.getName() + "()", context); + } + + + private boolean thisAccessExpressionApplicable(PsiElement expression) { + return PsiTreeUtil.isAncestor(myTargetClass, expression, false) && PsiUtil.getEnclosingStaticElement(expression, myTargetClass) == null; + } + + @NotNull protected String getCommandName() { return ConvertToInstanceMethodHandler.REFACTORING_NAME; } @Nullable public Map buildTypeParameterReplacements() { + if (myTargetParameter == null) { + return Collections.emptyMap(); + } final PsiClassType type = (PsiClassType)myTargetParameter.getType(); final PsiSubstitutor substitutor = type.resolveGenerics().getSubstitutor(); return calculateReplacementMap(substitutor, myTargetClass, myMethod); @@ -416,6 +512,7 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { return myMethod; } + @Nullable public PsiParameter getTargetParameter() { return myTargetParameter; } diff --git a/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/MethodReferenceUsageInfo.java b/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/MethodReferenceUsageInfo.java new file mode 100644 index 000000000000..a4b6e6db95d5 --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/MethodReferenceUsageInfo.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2017 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.refactoring.convertToInstanceMethod; + +import com.intellij.psi.PsiMethodCallExpression; +import com.intellij.psi.PsiMethodReferenceExpression; +import com.intellij.usageView.UsageInfo; + +public class MethodReferenceUsageInfo extends UsageInfo { + private final PsiMethodReferenceExpression myExpression; + private final boolean myApplicableBySecondSearch; + private PsiMethodCallExpression myReplacement; + + public MethodReferenceUsageInfo(PsiMethodReferenceExpression methodReferenceExpression, boolean bySecondSearch) { + super(methodReferenceExpression); + myExpression = methodReferenceExpression; + myApplicableBySecondSearch = bySecondSearch; + } + + public PsiMethodReferenceExpression getExpression() { + return myExpression; + } + + public boolean isApplicableBySecondSearch() { + return myApplicableBySecondSearch; + } + + public void setReplacement(PsiMethodCallExpression replacement) { + myReplacement = replacement; + } + + public PsiMethodCallExpression getReplacement() { + return myReplacement; + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java index e87889a5c136..e69233b24e3e 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java @@ -219,7 +219,9 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac myNameField.addDataChangedListener(this::update); myVisibilityPanel = createVisibilityPanel(); - myVisibilityPanel.registerUpDownActionsFor(myNameField); + if (!myNameField.hasSuggestions()) { + myVisibilityPanel.registerUpDownActionsFor(myNameField); + } final JPanel visibilityAndReturnType = new JPanel(new BorderLayout(2, 0)); if (!myTargetClass.isInterface()) { visibilityAndReturnType.add(myVisibilityPanel, BorderLayout.WEST); diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java index 3d79921c92b0..1ca615f4bd62 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java @@ -297,7 +297,7 @@ public class ExtractLightMethodObjectHandler { @NotNull @Override public String getVisibility() { - return PsiModifier.PUBLIC; + return PsiModifier.PACKAGE_LOCAL; } @Override diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineFieldDialog.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineFieldDialog.java index a1fb060ef3b6..efeb6978b08d 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineFieldDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineFieldDialog.java @@ -17,10 +17,9 @@ package com.intellij.refactoring.inline; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiField; -import com.intellij.psi.PsiReferenceExpression; -import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.*; import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.JavaRefactoringSettings; import com.intellij.refactoring.RefactoringBundle; @@ -39,7 +38,7 @@ public class InlineFieldDialog extends InlineOptionsWithSearchSettingsDialog { myInvokedOnReference = myReferenceExpression != null; setTitle(REFACTORING_NAME); - myOccurrencesNumber = initOccurrencesNumber(myField); + myOccurrencesNumber = getNumberOfOccurrences(myField); init(); } @@ -72,6 +71,11 @@ public class InlineFieldDialog extends InlineOptionsWithSearchSettingsDialog { return JavaRefactoringSettings.getInstance().INLINE_FIELD_THIS; } + @Override + protected boolean ignoreOccurrence(PsiReference reference) { + return PsiTreeUtil.getParentOfType(reference.getElement(), PsiImportStatementBase.class) == null; + } + @Override protected boolean isSearchInCommentsAndStrings() { return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_FIELD; diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodDialog.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodDialog.java index 45ef5b001ed6..a2d7f7ea3e07 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodDialog.java @@ -18,11 +18,10 @@ package com.intellij.refactoring.inline; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiJavaCodeReferenceElement; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.*; import com.intellij.psi.util.PsiFormatUtil; import com.intellij.psi.util.PsiFormatUtilBase; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.JavaRefactoringSettings; import com.intellij.refactoring.RefactoringBundle; @@ -47,7 +46,7 @@ public class InlineMethodDialog extends InlineOptionsWithSearchSettingsDialog { myInvokedOnReference = ref != null; setTitle(REFACTORING_NAME); - myOccurrencesNumber = initOccurrencesNumber(method); + myOccurrencesNumber = getNumberOfOccurrences(method); init(); } @@ -109,6 +108,11 @@ public class InlineMethodDialog extends InlineOptionsWithSearchSettingsDialog { return InlineMethodHandler.checkRecursive(myMethod) || myAllowInlineThisOnly; } + @Override + protected boolean ignoreOccurrence(PsiReference reference) { + return PsiTreeUtil.getParentOfType(reference.getElement(), PsiImportStatementBase.class) == null; + } + @Override protected boolean isInlineThis() { return JavaRefactoringSettings.getInstance().INLINE_METHOD_THIS; diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java index 4fe261b153de..f9edca96cfdf 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java @@ -511,14 +511,14 @@ public class MoveClassesOrPackagesProcessor extends BaseRefactoringProcessor { myElementsToMove[idx] = element; } + myNonCodeUsages = CommonMoveUtil.retargetUsages(usages, oldToNewElementsMapping); + for (PsiElement element : myElementsToMove) { if (element instanceof PsiClass) { MoveClassesOrPackagesUtil.finishMoveClass((PsiClass)element); } } - myNonCodeUsages = CommonMoveUtil.retargetUsages(usages, oldToNewElementsMapping); - if (myOpenInEditor) { EditorHelper.openFilesInEditor(myElementsToMove); } diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesUtil.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesUtil.java index ba1556161ef8..1a0d43908fd8 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesUtil.java @@ -242,13 +242,16 @@ public class MoveClassesOrPackagesUtil { file = moveDestination.findFile(file.getName()); - if (newPackage != null && file instanceof PsiClassOwner && !FileTypeUtils.isInServerPageFile(file) && !PsiUtil.isModuleFile(file)) { - // Do not rely on class instance identity retention after setPackageName (Scala) - String aClassName = aClass.getName(); - ((PsiClassOwner)file).setPackageName(newPackage.getQualifiedName()); - newClass = findClassByName((PsiClassOwner)file, aClassName); - LOG.assertTrue(newClass != null, "name:" + aClassName + " file:" + file + " classes:" + Arrays.toString(((PsiClassOwner)file).getClasses())); - } + } + + if (newPackage != null && file instanceof PsiClassOwner && !FileTypeUtils.isInServerPageFile(file) && + !PsiUtil.isModuleFile(file) && + !Comparing.strEqual(newPackage.getQualifiedName(), ((PsiClassOwner)file).getPackageName())) { + // Do not rely on class instance identity retention after setPackageName (Scala) + String aClassName = aClass.getName(); + ((PsiClassOwner)file).setPackageName(newPackage.getQualifiedName()); + newClass = findClassByName((PsiClassOwner)file, aClassName); + LOG.assertTrue(newClass != null, "name:" + aClassName + " file:" + file + " classes:" + Arrays.toString(((PsiClassOwner)file).getClasses())); } return newClass; } diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodDialog.java b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodDialog.java index 0646d43fde71..915362ccc749 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodDialog.java @@ -106,7 +106,7 @@ public class MoveInstanceMethodDialog extends MoveInstanceMethodDialogBase { textField.setEnabled(true); } - final PsiVariable variable = myVariables[selectedIndex]; + final Object variable = myVariables[selectedIndex]; if (variable instanceof PsiField) { final PsiField field = (PsiField)variable; final PsiClass hisClass = field.getContainingClass(); diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodDialogBase.java b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodDialogBase.java index a5b7faa910b0..44ba5aded37e 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodDialogBase.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodDialogBase.java @@ -42,7 +42,7 @@ import java.awt.*; */ public abstract class MoveInstanceMethodDialogBase extends MoveDialogBase { protected final PsiMethod myMethod; - protected final PsiVariable[] myVariables; + protected final Object[] myVariables; public JComponent getPreferredFocusedComponent() { return myList; @@ -52,7 +52,7 @@ public abstract class MoveInstanceMethodDialogBase extends MoveDialogBase { protected JavaVisibilityPanel myVisibilityPanel; protected final String myRefactoringName; - public MoveInstanceMethodDialogBase(PsiMethod method, PsiVariable[] variables, String refactoringName) { + public MoveInstanceMethodDialogBase(PsiMethod method, Object[] variables, String refactoringName) { super(method.getProject(), true); myMethod = method; myVariables = variables; @@ -142,12 +142,17 @@ public abstract class MoveInstanceMethodDialogBase extends MoveDialogBase { private static class MyListCellRenderer extends DefaultListCellRenderer { public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - final PsiVariable psiVariable = (PsiVariable)value; - final String text = PsiFormatUtil.formatVariable(psiVariable, - PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE, - PsiSubstitutor.EMPTY); - setIcon(psiVariable.getIcon(0)); - setText(text); + if (value instanceof PsiVariable) { + final PsiVariable psiVariable = (PsiVariable)value; + final String text = PsiFormatUtil.formatVariable(psiVariable, + PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE, + PsiSubstitutor.EMPTY); + setIcon(psiVariable.getIcon(0)); + setText(text); + } + else if (value instanceof String) { + setText((String)value); + } return this; } } diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java index 26338d0d79cb..e4fde5f19f91 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java @@ -28,6 +28,7 @@ import com.intellij.psi.javadoc.PsiDocTagValue; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.BaseRefactoringProcessor; @@ -120,12 +121,12 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{ if (myTargetVariable instanceof PsiParameter) { PsiParameter parameter = (PsiParameter)myTargetVariable; + final int index = myMethod.getParameterList().getParameterIndex(parameter); for (final UsageInfo usageInfo : usages) { if (usageInfo instanceof MethodCallUsageInfo) { final PsiElement methodCall = ((MethodCallUsageInfo)usageInfo).getMethodCallExpression(); if (methodCall instanceof PsiMethodCallExpression) { final PsiExpression[] expressions = ((PsiMethodCallExpression)methodCall).getArgumentList().getExpressions(); - final int index = myMethod.getParameterList().getParameterIndex(parameter); if (index < expressions.length) { PsiExpression instanceValue = expressions[index]; instanceValue = RefactoringUtil.unparenthesizeExpression(instanceValue); @@ -136,8 +137,8 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{ conflicts.putValue(instanceValue, message); } } - } else if (methodCall instanceof PsiMethodReferenceExpression) { - conflicts.putValue(methodCall, "Method reference would be broken after move"); + } else if (methodCall instanceof PsiMethodReferenceExpression && shouldBeExpandedToLambda((PsiMethodReferenceExpression)methodCall, index)) { + conflicts.putValue(methodCall, RefactoringBundle.message("expand.method.reference.warning")); } } } @@ -151,6 +152,22 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{ return showConflicts(conflicts, usages); } + /** + * If collapse by second search is possible, then it's possible not to expand + */ + private boolean shouldBeExpandedToLambda(PsiMethodReferenceExpression referenceExpression, int index) { + PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(referenceExpression.getFunctionalInterfaceType()); + PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); + if (interfaceMethod != null) { + MethodSignature methodSignature = interfaceMethod.getSignature(LambdaUtil.getSubstitutor(interfaceMethod, resolveResult)); + if (index == 0 && methodSignature.getParameterTypes().length > 0 && + methodSignature.getParameterTypes()[0].isAssignableFrom(myMethod.getParameterList().getParameters()[0].getType())) { + return false; + } + } + return true; + } + @NotNull protected UsageInfo[] findUsages() { final PsiManager manager = myMethod.getManager(); @@ -220,6 +237,7 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{ myTargetClass = (PsiClass) elements[2]; } + @NotNull protected String getCommandName() { return RefactoringBundle.message("move.instance.method.command"); } @@ -246,20 +264,32 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{ else if (expression instanceof PsiMethodReferenceExpression) { PsiMethodReferenceExpression methodReferenceExpression = (PsiMethodReferenceExpression)expression; PsiExpression qualifierExpression = methodReferenceExpression.getQualifierExpression(); - String exprText; - if (myTargetVariable instanceof PsiParameter || - qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifierExpression).resolve() == myMethod.getContainingClass()) { - exprText = myTargetVariable.getType().getCanonicalText(); - } - else if (qualifierExpression instanceof PsiReferenceExpression) { - exprText = qualifierExpression.getText() + "." + myTargetVariable.getName(); + + if (myTargetVariable instanceof PsiParameter && shouldBeExpandedToLambda(methodReferenceExpression, myMethod.getParameterList().getParameterIndex((PsiParameter)myTargetVariable))) { + PsiLambdaExpression lambdaExpression = LambdaRefactoringUtil.convertMethodReferenceToLambda(methodReferenceExpression, false, true); + if (lambdaExpression != null) { + List returnExpressions = LambdaUtil.getReturnExpressions(lambdaExpression); + if (!returnExpressions.isEmpty()) { + correctMethodCall((PsiMethodCallExpression)returnExpressions.get(0), false); + } + } } else { - exprText = myTargetVariable.getName(); + String exprText; + if (myTargetVariable instanceof PsiParameter || + qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifierExpression).resolve() == myMethod.getContainingClass()) { + exprText = myTargetVariable.getType().getCanonicalText(); + } + else if (qualifierExpression instanceof PsiReferenceExpression) { + exprText = qualifierExpression.getText() + "." + myTargetVariable.getName(); + } + else { + exprText = myTargetVariable.getName(); + } + PsiExpression newQualifier = JavaPsiFacade.getInstance(myProject).getElementFactory().createExpressionFromText(exprText, null); + ((PsiMethodReferenceExpression)expression).setQualifierExpression(newQualifier); + JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(expression); } - PsiExpression newQualifier = JavaPsiFacade.getInstance(myProject).getElementFactory().createExpressionFromText(exprText, null); - ((PsiMethodReferenceExpression)expression).setQualifierExpression( - (PsiExpression)JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(newQualifier)); } } else if (usage instanceof JavadocUsageInfo) { @@ -474,14 +504,7 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{ return; } if (myTargetVariable.equals(resolved)) { - PsiThisExpression thisExpression = RefactoringChangeUtil.createThisExpression(manager, PsiTreeUtil.isAncestor(myMethod, - PsiTreeUtil - .getParentOfType( - expression, - PsiClass.class), - true) - ? myTargetClass - : null); + PsiThisExpression thisExpression = RefactoringChangeUtil.createThisExpression(manager, PsiTreeUtil.isAncestor(myMethod, PsiTreeUtil.getParentOfType(expression, PsiClass.class), true) ? myTargetClass : null); replaceMap.put(expression, thisExpression); return; } diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodViewDescriptor.java b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodViewDescriptor.java index 5665c5621289..2a42cc1803f5 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodViewDescriptor.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodViewDescriptor.java @@ -31,10 +31,9 @@ public class MoveInstanceMethodViewDescriptor extends UsageViewDescriptorAdapter private final PsiVariable myTargetVariable; private final PsiClass myTargetClass; - public MoveInstanceMethodViewDescriptor( - PsiMethod method, - PsiVariable targetVariable, - PsiClass targetClass) { + public MoveInstanceMethodViewDescriptor(PsiMethod method, + PsiVariable targetVariable, + PsiClass targetClass) { super(); myMethod = method; myTargetVariable = targetVariable; @@ -43,7 +42,7 @@ public class MoveInstanceMethodViewDescriptor extends UsageViewDescriptorAdapter @NotNull public PsiElement[] getElements() { - return new PsiElement[] {myMethod, myTargetVariable, myTargetClass}; + return myTargetVariable == null ? new PsiElement[] {myTargetClass} : new PsiElement[] {myMethod, myTargetVariable, myTargetClass}; } public String getProcessedElementsHeader() { diff --git a/java/java-impl/src/com/intellij/testIntegration/intention/MoveInitializerToSetUpMethodAction.java b/java/java-impl/src/com/intellij/testIntegration/intention/MoveInitializerToSetUpMethodAction.java index fdaa574c2871..d3c6c07977a0 100644 --- a/java/java-impl/src/com/intellij/testIntegration/intention/MoveInitializerToSetUpMethodAction.java +++ b/java/java-impl/src/com/intellij/testIntegration/intention/MoveInitializerToSetUpMethodAction.java @@ -20,13 +20,11 @@ import com.intellij.codeInsight.TestFrameworks; import com.intellij.codeInsight.intention.impl.BaseMoveInitializerToMethodAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.testIntegration.JavaTestFramework; import com.intellij.testIntegration.TestFramework; -import com.intellij.testIntegration.TestIntegrationUtils; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -53,25 +51,23 @@ public class MoveInitializerToSetUpMethodAction extends BaseMoveInitializerToMet @Override public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - final boolean isAvailable = super.isAvailable(project, editor, element) && TestIntegrationUtils.isTest(element); + final boolean isAvailable = super.isAvailable(project, editor, element); if (isAvailable) { final PsiField field = PsiTreeUtil.getParentOfType(element, PsiField.class); LOG.assertTrue(field != null); final PsiClass aClass = field.getContainingClass(); LOG.assertTrue(aClass != null); + TestFramework testFramework = TestFrameworks.detectFramework(aClass); final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); - for (TestFramework framework : Extensions.getExtensions(TestFramework.EXTENSION_NAME)) { - if (framework instanceof JavaTestFramework && framework.isTestClass(aClass)) { - try { - ((JavaTestFramework)framework).createSetUpPatternMethod(elementFactory); - return true; - } - catch (Exception e) { - return false; - } + if (testFramework instanceof JavaTestFramework) { + try { + ((JavaTestFramework)testFramework).createSetUpPatternMethod(elementFactory); + return testFramework.isTestClass(aClass) || testFramework.findSetUpMethod(aClass) instanceof PsiMethod; + } + catch (Exception e) { + return false; } } - return true; } return false; } @@ -85,7 +81,14 @@ public class MoveInitializerToSetUpMethodAction extends BaseMoveInitializerToMet @NotNull @Override protected Collection getOrCreateMethods(@NotNull Project project, @NotNull Editor editor, PsiFile file, @NotNull PsiClass aClass) { - final PsiMethod setUpMethod = TestFrameworks.getInstance().findOrCreateSetUpMethod(aClass); - return setUpMethod == null ? Collections.emptyList() : Arrays.asList(setUpMethod); + TestFramework testFramework = TestFrameworks.detectFramework(aClass); + PsiElement setUpMethod = null; + if (testFramework != null) { + setUpMethod = testFramework.findSetUpMethod(aClass); + if (setUpMethod == null) { + setUpMethod = testFramework.findOrCreateSetUpMethod(aClass); + } + } + return setUpMethod instanceof PsiMethod ? Collections.singletonList((PsiMethod)setUpMethod) : Collections.emptyList(); } } diff --git a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java index f5e581dc9bcf..3373879cb6bd 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,6 @@ import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashMap; import gnu.trove.THashSet; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,50 +39,19 @@ import java.util.*; * @author max */ public class AnnotationUtil { - /** - * The full qualified name of the standard Nullable annotation. - */ public static final String NULLABLE = "org.jetbrains.annotations.Nullable"; - - /** - * The full qualified name of the standard NotNull annotation. - */ public static final String NOT_NULL = "org.jetbrains.annotations.NotNull"; - @NonNls public static final String NOT_NULL_SIMPLE_NAME = "NotNull"; - - @NonNls public static final String NULLABLE_SIMPLE_NAME = "Nullable"; - - /** - * The full qualified name of the standard NonNls annotation. - * - * @since 5.0.1 - */ public static final String NON_NLS = "org.jetbrains.annotations.NonNls"; public static final String NLS = "org.jetbrains.annotations.Nls"; - public static final String PROPERTY_KEY = "org.jetbrains.annotations.PropertyKey"; - @NonNls public static final String PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER = "resourceBundle"; - @NonNls public static final String NON_NLS_SIMPLE_NAME = "NonNls"; - @NonNls public static final String PROPERTY_KEY_SIMPLE_NAME = "PropertyKey"; + public static final String PROPERTY_KEY = "org.jetbrains.annotations.PropertyKey"; + public static final String PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER = "resourceBundle"; public static final String TEST_ONLY = "org.jetbrains.annotations.TestOnly"; - @NonNls public static final String TEST_ONLY_SIMPLE_NAME = "TestOnly"; public static final String LANGUAGE = "org.intellij.lang.annotations.Language"; - public static final Set ALL_ANNOTATIONS; - - @NonNls private static final String[] SIMPLE_NAMES = - {NOT_NULL_SIMPLE_NAME, NULLABLE_SIMPLE_NAME, NON_NLS_SIMPLE_NAME, PROPERTY_KEY_SIMPLE_NAME, TEST_ONLY_SIMPLE_NAME, - "Language", "Identifier", "Pattern", "PrintFormat", "RegExp", "Subst"}; - - static { - ALL_ANNOTATIONS = new HashSet<>(2); - ALL_ANNOTATIONS.add(NULLABLE); - ALL_ANNOTATIONS.add(NOT_NULL); - } - @Nullable public static PsiAnnotation findAnnotation(@Nullable PsiModifierListOwner listOwner, @NotNull String... annotationNames) { return findAnnotation(listOwner, false, annotationNames); @@ -285,37 +253,41 @@ public class AnnotationUtil { public static boolean isAnnotated(@NotNull PsiModifierListOwner listOwner, @NotNull Collection annotations, - final boolean checkHierarchy) { + boolean checkHierarchy) { return isAnnotated(listOwner, annotations, checkHierarchy, true); } public static boolean isAnnotated(@NotNull PsiModifierListOwner listOwner, @NotNull Collection annotations, - final boolean checkHierarchy, + boolean checkHierarchy, boolean skipExternal) { - for (String annotation : annotations) { - if (isAnnotated(listOwner, annotation, checkHierarchy, skipExternal)) return true; - } - return false; + return annotations.stream().anyMatch(annotation -> isAnnotated(listOwner, annotation, checkHierarchy, skipExternal)); } - public static boolean isAnnotated(@NotNull PsiModifierListOwner listOwner, @NonNls @NotNull String annotationFQN, boolean checkHierarchy) { + public static boolean isAnnotated(@NotNull PsiModifierListOwner listOwner, @NotNull String annotationFQN, boolean checkHierarchy) { return isAnnotated(listOwner, annotationFQN, checkHierarchy, true, null); } - public static boolean isAnnotated(@NotNull PsiModifierListOwner listOwner, @NonNls @NotNull String annotationFQN, boolean checkHierarchy, + public static boolean isAnnotated(@NotNull PsiModifierListOwner listOwner, + @NotNull String annotationFQN, + boolean checkHierarchy, boolean skipExternal) { return isAnnotated(listOwner, annotationFQN, checkHierarchy, skipExternal, null); } private static boolean isAnnotated(@NotNull PsiModifierListOwner listOwner, - @NonNls @NotNull String annotationFQN, - boolean checkHierarchy, final boolean skipExternal, @Nullable Set processed) { + @NotNull String annotationFQN, + boolean checkHierarchy, + boolean skipExternal, + @Nullable Set processed) { if (!listOwner.isValid()) return false; - final PsiModifierList modifierList = listOwner.getModifierList(); + + PsiModifierList modifierList = listOwner.getModifierList(); if (modifierList == null) return false; + PsiAnnotation annotation = modifierList.findAnnotation(annotationFQN); if (annotation != null) return true; + if (!skipExternal) { final Project project = listOwner.getProject(); if (ExternalAnnotationsManager.getInstance(project).findExternalAnnotation(listOwner, annotationFQN) != null || @@ -323,6 +295,7 @@ public class AnnotationUtil { return true; } } + if (checkHierarchy) { if (listOwner instanceof PsiMethod) { PsiMethod method = (PsiMethod)listOwner; @@ -332,7 +305,8 @@ public class AnnotationUtil { for (PsiMethod superMethod : superMethods) { if (isAnnotated(superMethod, annotationFQN, true, skipExternal, processed)) return true; } - } else if (listOwner instanceof PsiClass) { + } + else if (listOwner instanceof PsiClass) { final PsiClass clazz = (PsiClass)listOwner; if (processed == null) processed = new THashSet<>(); if (!processed.add(clazz)) return false; @@ -342,6 +316,7 @@ public class AnnotationUtil { } } } + return false; } @@ -355,10 +330,6 @@ public class AnnotationUtil { JavaPsiFacade.getInstance(project).findClass(annotationFQN, elt.getResolveScope()) != null; } - public static boolean isJetbrainsAnnotation(@NonNls @NotNull String simpleName) { - return ArrayUtil.find(SIMPLE_NAMES, simpleName) != -1; - } - /** * Works similar to #isAnnotated(PsiModifierListOwner, Collection) but supports FQN patters * like "javax.ws.rs.*". Supports ending "*" only. @@ -545,10 +516,10 @@ public class AnnotationUtil { } @Nullable - public static PsiNameValuePair findDeclaredAttribute(@NotNull PsiAnnotation annotation, @NonNls @Nullable("null means 'value'") String attributeName) { + public static PsiNameValuePair findDeclaredAttribute(@NotNull PsiAnnotation annotation, @Nullable("null means 'value'") String attributeName) { if (PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(attributeName)) attributeName = null; for (PsiNameValuePair attribute : annotation.getParameterList().getAttributes()) { - @NonNls final String name = attribute.getName(); + final String name = attribute.getName(); if (Comparing.equal(name, attributeName) || attributeName == null && PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(name)) { return attribute; } @@ -650,4 +621,17 @@ public class AnnotationUtil { map.remove(CommonClassNames.JAVA_LANG_OVERRIDE); return map; } -} + + // + /** @deprecated use {@link NullableNotNullManager} (to be removed in IDEA 2018) */ + public static final Set ALL_ANNOTATIONS = ContainerUtil.newTroveSet(NULLABLE, NOT_NULL); + + private static final String[] SIMPLE_NAMES = + {"NotNull", "Nullable", "NonNls", "PropertyKey", "TestOnly", "Language", "Identifier", "Pattern", "PrintFormat", "RegExp", "Subst"}; + + /** @deprecated wrong; do not use (to be removed in IDEA 2018) */ + public static boolean isJetbrainsAnnotation(@NotNull String simpleName) { + return ArrayUtil.find(SIMPLE_NAMES, simpleName) != -1; + } + // +} \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java b/java/java-psi-api/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java index 951962778627..849ed832cdb4 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. diff --git a/java/java-psi-api/src/com/intellij/pom/java/LanguageLevel.java b/java/java-psi-api/src/com/intellij/pom/java/LanguageLevel.java index 66ed4b51a787..ed493cc208b6 100644 --- a/java/java-psi-api/src/com/intellij/pom/java/LanguageLevel.java +++ b/java/java-psi-api/src/com/intellij/pom/java/LanguageLevel.java @@ -38,7 +38,7 @@ public enum LanguageLevel { JDK_1_6("Java 6", JavaCoreBundle.message("jdk.1.6.language.level.description"), "1.6", "6"), JDK_1_7("Java 7", JavaCoreBundle.message("jdk.1.7.language.level.description"), "1.7", "7"), JDK_1_8("Java 8", JavaCoreBundle.message("jdk.1.8.language.level.description"), "1.8", "8"), - JDK_1_9("Java 9", JavaCoreBundle.message("jdk.1.9.language.level.description"), "9"), + JDK_1_9("Java 9", JavaCoreBundle.message("jdk.1.9.language.level.description"), "9", "1.9"), JDK_X("Java X", JavaCoreBundle.message("jdk.X.language.level.description"), ""); public static final LanguageLevel HIGHEST = JDK_1_9; diff --git a/java/java-psi-api/src/com/intellij/psi/PsiClassType.java b/java/java-psi-api/src/com/intellij/psi/PsiClassType.java index 40715e11ffb9..ccd277dee6c8 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiClassType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiClassType.java @@ -31,7 +31,7 @@ import org.jetbrains.annotations.Nullable; */ public abstract class PsiClassType extends PsiType { public static final PsiClassType[] EMPTY_ARRAY = new PsiClassType[0]; - public static final ArrayFactory ARRAY_FACTORY = count -> new PsiClassType[count]; + public static final ArrayFactory ARRAY_FACTORY = count -> count == 0 ? EMPTY_ARRAY : new PsiClassType[count]; protected final LanguageLevel myLanguageLevel; @@ -289,7 +289,7 @@ public abstract class PsiClassType extends PsiType { }; } - public static abstract class Stub extends PsiClassType { + public abstract static class Stub extends PsiClassType { protected Stub(LanguageLevel languageLevel, @NotNull PsiAnnotation[] annotations) { super(languageLevel, annotations); } diff --git a/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java b/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java index c02649b0fa68..b1e85b73ca6b 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java @@ -738,7 +738,18 @@ public class RedundantCastUtil { PsiExpression lExpression = assignment.getLExpression(); return lExpression instanceof PsiArrayAccessExpression && PsiTreeUtil.isAncestor(lExpression, parent, false) && - !PsiTreeUtil.isAncestor(((PsiArrayAccessExpression)lExpression).getIndexExpression(), element, false); + !isIndexExpression(element, (PsiArrayAccessExpression)lExpression); + } + + private static boolean isIndexExpression(PsiElement element, PsiArrayAccessExpression arrayAccessExpression) { + if (PsiTreeUtil.isAncestor(arrayAccessExpression.getIndexExpression(), element, false)) { + return true; + } + PsiExpression arrayExpression = arrayAccessExpression.getArrayExpression(); + if (arrayExpression instanceof PsiArrayAccessExpression) { + return isIndexExpression(element, (PsiArrayAccessExpression)arrayExpression); + } + return false; } } diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ClosureFolding.java b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ClosureFolding.java index e42fba27a024..78390e265777 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ClosureFolding.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ClosureFolding.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -24,7 +24,6 @@ import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.Function; import com.intellij.util.ObjectUtils; import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsBase.java b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsBase.java index 6e039fc87b65..e36f96fccd5d 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsBase.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java index 0d32ade8efa1..1be609b87541 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java @@ -25,7 +25,6 @@ import com.intellij.psi.impl.source.tree.*; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.*; -import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.util.ObjectUtils; import com.intellij.util.SmartList; @@ -250,7 +249,9 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl // neighbouring type annotations are logical part of this type element and should be dropped PsiImplUtil.markTypeAnnotations(this); PsiElement result = super.replace(newElement); - PsiImplUtil.deleteTypeAnnotations((PsiTypeElement)result); + if (result instanceof PsiTypeElement) { + PsiImplUtil.deleteTypeAnnotations((PsiTypeElement)result); + } return result; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/TopLevelParentNoParameters.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/TopLevelParentNoParameters.java new file mode 100644 index 000000000000..0431d525cb85 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/TopLevelParentNoParameters.java @@ -0,0 +1,26 @@ + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.logging.Logger; + +class MyTest +{ + private final static Logger LOGGER = Logger.getLogger(MyTest.class.getName()); + + public static void test(List> testList) { + testList.forEach( MyTest.bind(MyTest.cast(LOGGER::info), iterable -> "")); + } + + private static TestConsumer bind(Consumer delegate, Function function) { + return null; + } + + private static Consumer cast(Consumer consumer) + { + return consumer; + } + + private interface TestConsumer extends Consumer { } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/afterOverload.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/afterOverload.java new file mode 100644 index 000000000000..251ec4b18bc6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/afterOverload.java @@ -0,0 +1,11 @@ +// "Create local variable 'xyz'" "true" +interface Other { + void add(int x, T y); + void add(T y); +} +class A { + public void foo(Other other) { + String xyz; + other.add(xyz); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/beforeOverload.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/beforeOverload.java new file mode 100644 index 000000000000..ac0d06ebddb4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/beforeOverload.java @@ -0,0 +1,10 @@ +// "Create local variable 'xyz'" "true" +interface Other { + void add(int x, T y); + void add(T y); +} +class A { + public void foo(Other other) { + other.add(xyz); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2.java index fe9b8f588763..fb1ccec58f17 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2.java @@ -1,5 +1,5 @@ module M { - exports my.api; exports my.api to M2, M4; exports my.api to M6; + exports my.api; } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2_after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2_after.java deleted file mode 100644 index a773247df415..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2_after.java +++ /dev/null @@ -1,4 +0,0 @@ -module M { - exports my.api; - exports my.api to M6, M2, M4; -} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens2_after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens2_after.java deleted file mode 100644 index 321668b41336..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens2_after.java +++ /dev/null @@ -1,4 +0,0 @@ -module M { - opens my.api; - opens my.api to M6, M2, M4; -} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/afterJUnit4WithBeforeOnly.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/afterJUnit4WithBeforeOnly.java new file mode 100644 index 000000000000..a693577921ce --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/afterJUnit4WithBeforeOnly.java @@ -0,0 +1,10 @@ +// "Move initializer to setUp method" "true" +public class X { + int i; + + @org.junit.Before + public void setUp() throws Exception { + + i = 7; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforeJUnit4WithBeforeOnly.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforeJUnit4WithBeforeOnly.java new file mode 100644 index 000000000000..5af0027632a3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforeJUnit4WithBeforeOnly.java @@ -0,0 +1,9 @@ +// "Move initializer to setUp method" "true" +public class X { + int i = 7; + + @org.junit.Before + public void setUp() throws Exception { + + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterContinueOr.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterContinueOr.java index 99b377a621e6..a9ceb8b183af 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterContinueOr.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterContinueOr.java @@ -8,7 +8,7 @@ public class Main { } public long test(List collection) { - long i = collection.stream().filter(person -> !(person == null || person.getAge() < 10)).mapToLong(Person::getAge).sum(); + long i = collection.stream().filter(person -> person != null && person.getAge() >= 10).mapToLong(Person::getAge).sum(); return i; } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/invertIfCondition/afterEmptyParenthesis.java b/java/java-tests/testData/codeInsight/invertIfCondition/afterEmptyParenthesis.java new file mode 100644 index 000000000000..f7fcfffc82bc --- /dev/null +++ b/java/java-tests/testData/codeInsight/invertIfCondition/afterEmptyParenthesis.java @@ -0,0 +1,11 @@ +// "Invert 'if' condition" "true" +class A { + public boolean foo() { + if (!()) { + return true; + } + else { + return false; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/invertIfCondition/afterNull.java b/java/java-tests/testData/codeInsight/invertIfCondition/afterNull.java new file mode 100644 index 000000000000..208552c5bd18 --- /dev/null +++ b/java/java-tests/testData/codeInsight/invertIfCondition/afterNull.java @@ -0,0 +1,11 @@ +// "Invert 'if' condition" "true" +class A { + public boolean foo() { + if (!null) { + return true; + } + else { + return false; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/invertIfCondition/beforeEmptyParenthesis.java b/java/java-tests/testData/codeInsight/invertIfCondition/beforeEmptyParenthesis.java new file mode 100644 index 000000000000..87b2ce7888b8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/invertIfCondition/beforeEmptyParenthesis.java @@ -0,0 +1,9 @@ +// "Invert 'if' condition" "true" +class A { + public boolean foo() { + if (()) + return false; + else + return true; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/invertIfCondition/beforeNull.java b/java/java-tests/testData/codeInsight/invertIfCondition/beforeNull.java new file mode 100644 index 000000000000..584af553ad79 --- /dev/null +++ b/java/java-tests/testData/codeInsight/invertIfCondition/beforeNull.java @@ -0,0 +1,9 @@ +// "Invert 'if' condition" "true" +class A { + public boolean foo() { + if (null) + return false; + else + return true; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compiler/completionOrdering/testExpectedByTypeAreFirst/Foo.java b/java/java-tests/testData/compiler/completionOrdering/testExpectedByTypeAreFirst/Foo.java new file mode 100644 index 000000000000..269aa3ca9741 --- /dev/null +++ b/java/java-tests/testData/compiler/completionOrdering/testExpectedByTypeAreFirst/Foo.java @@ -0,0 +1,35 @@ +class Foo { + public String someMethod1() { + return null; + } + + public String someMethod2(String s) { + return null; + } + + public Runnable someMethod3() { + return null; + } + + void m() { + someMethod1(); + someMethod1(); + someMethod1(); + + someMethod2(""); + someMethod2(""); + someMethod2(""); + someMethod2(""); + + someMethod3(); + someMethod3(); + someMethod3(); + someMethod3(); + someMethod3(); + } + + void mm(Foo f) { + + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/compiler/completionOrdering/testHelperMethodIsNotAffected/Foo.java b/java/java-tests/testData/compiler/completionOrdering/testHelperMethodIsNotAffected/Foo.java new file mode 100644 index 000000000000..5f9ba114e237 --- /dev/null +++ b/java/java-tests/testData/compiler/completionOrdering/testHelperMethodIsNotAffected/Foo.java @@ -0,0 +1,61 @@ +class Foo { + + public static void someMethod1() { + + } + + public static void someMethod2(String string) { + + } + + void m() { + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + nonNull(""); + + someMethod1(); + someMethod1(); + someMethod1(); + someMethod2(""); + someMethod2(""); + someMethod2(""); + someMethod2(""); + someMethod2(""); + + + + } + + public static T nonNull(T t) { + assert t != null; + return t; + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ContractConstructor.java b/java/java-tests/testData/inspection/dataFlow/fixture/ContractConstructor.java index c29ed07070d1..fc1d5fa6cae8 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/ContractConstructor.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ContractConstructor.java @@ -7,8 +7,8 @@ class CandidateInfo { } static void test() { - new CandidateInfo(null, true, false); - new CandidateInfo(null, true, true); + new CandidateInfo(null, true, false); + new CandidateInfo(null, true, true); new CandidateInfo(null, false, true); new CandidateInfo(new Object(), true, true); diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/CustomContracts.java b/java/java-tests/testData/inspection/dataFlow/fixture/CustomContracts.java new file mode 100644 index 000000000000..942a7c3173bd --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/CustomContracts.java @@ -0,0 +1,30 @@ +public class CustomContracts { + public void testSubstring(String s) { + if (s.substring(-1).length() == 0) { + System.out.println("Oops"); + } + } + + public void testSubstring2(String s, int index) { + if (s.substring(0, index).length() == 0 || index < 0) { + System.out.println("Oops"); + } + } + + public void testSubstring3(String s, int index) { + if (s.substring(3, index).equals("foo") || index == 1) { + System.out.println("Oops"); + } + } + + public void testCharAt(String s) { + int index = 0; + while (Character.isDigit(s.charAt(index))) { + index++; + } + + if (index == 0 || index == s.length()) { + System.out.println("Wrong"); + } + } +} diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/DoubleNaN.java b/java/java-tests/testData/inspection/dataFlow/fixture/DoubleNaN.java new file mode 100644 index 000000000000..714035000412 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/DoubleNaN.java @@ -0,0 +1,9 @@ +public class DoubleNaN { + void test() { + double x = Double.NaN; + double y = Double.NaN; + if(x >= y) { + System.out.println("oops"); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/FlushVariableOnStackToNotNullType.java b/java/java-tests/testData/inspection/dataFlow/fixture/FlushVariableOnStackToNotNullType.java new file mode 100644 index 000000000000..c757c8d09861 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/FlushVariableOnStackToNotNullType.java @@ -0,0 +1,45 @@ +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; + +public class FlushVariableOnStackToNotNullType { + private String str; + + @Contract(value = "null -> true", pure = true) + public static boolean isEmpty(@Nullable String s) { + return s == null || s.equals(""); + } + + interface State { + @Nullable + String get() throws IOException; + } + + @Nullable + public String getMessage(State currentState, boolean x, @NotNull String message) { + String errorMessage = null; + if (x) { + errorMessage = message; + } + + try { + errorMessage = currentState.get(); + } catch (IOException ignored) { + } + + if (isEmpty(errorMessage) && !isEmpty(str)) { + errorMessage = "foo"; + } + + if (isEmpty(errorMessage)) { + try { + errorMessage = currentState.get(); + } catch (IOException ignored) { + } + } + + return errorMessage; + } +} diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/GenericParameterNullity.java b/java/java-tests/testData/inspection/dataFlow/fixture/GenericParameterNullity.java index e25c89ab650f..500b5e4bfc55 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/GenericParameterNullity.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/GenericParameterNullity.java @@ -8,7 +8,7 @@ class Test { String a = notNull(getNullable()); @NotNull - String b = notNull(null); + String b = notNull(null); } @Nullable diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/LongRangeKnownMethods.java b/java/java-tests/testData/inspection/dataFlow/fixture/LongRangeKnownMethods.java index de8b54e5f43a..db2d9d81952f 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/LongRangeKnownMethods.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/LongRangeKnownMethods.java @@ -1,5 +1,6 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Scanner; public class LongRangeKnownMethods { void testIndexOf(String s) { @@ -81,7 +82,7 @@ public class LongRangeKnownMethods { } void testEqualsIgnoreCase(String s) { - if(s.equalsIgnoreCase("xyz") && s.isEmpty()) { + if(s.equalsIgnoreCase("xyz") && s.isEmpty()) { System.out.println("Never"); } } @@ -150,4 +151,41 @@ public class LongRangeKnownMethods { System.out.println("impossible"); } } + + void testStringComparison(String name) { + // Parentheses misplaced -- found in AndroidStudio + if (!(name.equals("layout_width") && !(name.equals("layout_height")) && + !(name.equals("id")))) { + System.out.println("ok"); + } + } + + void testFlush(MyReader r) { + if(r.getValue().equals("abc")) { + r.readNext(); + if(r.getValue().equals("abcd")) { + System.out.println("ok"); + } + } + } + + void testNoFlush(MyReader r) { + if(r.getValue().equals("abc")) { + if(r.getValue().equals("abcd")) { + System.out.println("ok"); + } + } + } + + static class MyReader { + private String value = ""; + + final String getValue() { + return value; + } + + void readNext() { + value = new Scanner(System.in).next(); + } + } } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/LongRangeLoop.java b/java/java-tests/testData/inspection/dataFlow/fixture/LongRangeLoop.java index 0cadb272e057..755042414fff 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/LongRangeLoop.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/LongRangeLoop.java @@ -17,6 +17,51 @@ public class LongRangeLoop { if(i == 20) { System.out.println("Oops"); } + if(i < -10) { + System.out.println("Oops"); + } + } + } + + public static void loopOrigin(long i) { + if(i > 0) { + for (long j = i; j <= 1000; ++j) { + if (j < 0) { + System.out.println("Impossible"); + } + } + } + } + + public static void loopUnknownBoundIncluding(int bound) { + for (int i = 0; i <= bound; i++) { + if (i == -1) { + System.out.println("Overflow detected: bound was Integer.MAX_VALUE"); + } + } + } + + public static void loopUnknownBoundExcluding(int bound) { + for (int i = 0; i < bound; i++) { + if (i == -1) { + System.out.println("Impossible even if bound is Integer.MAX_VALUE"); + } + } + } + + public static void loopUnknownBoundIncludingLong(int bound) { + for (long i = 0; i <= bound; i++) { + if (i == -1) { + System.out.println("Impossible even if bound is Integer.MAX_VALUE"); + } + } + } + + public void IDEA168715() { + for (int i = 1; i < 100; i++) { + if (i == 0) { + System.out.print("Dead code"); + } } } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/OptionalGetWithoutIsPresent.java b/java/java-tests/testData/inspection/dataFlow/fixture/OptionalGetWithoutIsPresent.java index 9642644ebcf3..7de03e46e8e2 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/OptionalGetWithoutIsPresent.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/OptionalGetWithoutIsPresent.java @@ -82,7 +82,7 @@ class OptionalWithoutIsPresent { } if (maybe.isPresent()) { maybe = Optional.empty(); - System.out.println(maybe.get()); + System.out.println(maybe.get()); } boolean b = ((maybe.isPresent())) && maybe.get() == 1; boolean c = (!maybe.isPresent()) || maybe.get() == 1; @@ -118,7 +118,7 @@ class OptionalWithoutIsPresent { boolean absent = !present; boolean otherAbsent = !!absent; if(otherAbsent) { - System.out.println(opt.get()); + System.out.println(opt.get()); } else { System.out.println(opt.get()); } @@ -151,12 +151,12 @@ class OptionalWithoutIsPresent { o2 = getOptional(); org.junit.Assert.assertTrue(!o2.isPresent()); - System.out.println(o2.get()); + System.out.println(o2.get()); } private void checkAsserts2() { Optional o3 = Optional.empty(); - org.testng.Assert.assertTrue(o3.isPresent()); + org.testng.Assert.assertTrue(o3.isPresent()); System.out.println(o3.get()); } @@ -180,7 +180,7 @@ class OptionalWithoutIsPresent { } else { test = Optional.empty(); } - System.out.println(test.get()); + System.out.println(test.get()); } @@ -228,7 +228,7 @@ class OptionalWithoutIsPresent { void order(Optional order, boolean b) { order.ifPresent(o -> System.out.println(order.get())); - System.out.println(order.orElseGet(() -> order.get().trim())); + System.out.println(order.orElseGet(() -> order.get().trim())); } public static void two(Optional o1,Optional o2) { @@ -316,6 +316,14 @@ class OptionalWithoutIsPresent { return optional.isPresent() ? opt2.get() : ""; } + com.google.common.base.Optional field; + + void guavaFieldTest() { + if(field.isPresent()) { + System.out.println(field.get()); + } + } + void guavaTest(com.google.common.base.Optional opt, String s) { System.out.println(opt.get()); if(opt.isPresent()) { @@ -359,8 +367,8 @@ class OptionalWithoutIsPresent { public void testThrowFail(Optional arg) { if(!arg.isPresent()) { - System.out.println(arg.orElseThrow(IllegalAccessError::new)); + System.out.println(arg.orElseThrow(IllegalAccessError::new)); } - String res = Optional.empty().orElseThrow(RuntimeException::new); + String res = Optional.empty().orElseThrow(RuntimeException::new); } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/javaReflectionInvocation/ConstructorParamTypes.java b/java/java-tests/testData/inspection/javaReflectionInvocation/ConstructorParamTypes.java index 57a33f282be6..c2a1c41fc07e 100644 --- a/java/java-tests/testData/inspection/javaReflectionInvocation/ConstructorParamTypes.java +++ b/java/java-tests/testData/inspection/javaReflectionInvocation/ConstructorParamTypes.java @@ -1,3 +1,4 @@ +import java.io.Serializable; import java.lang.reflect.Constructor; import java.util.*; @@ -32,9 +33,9 @@ class ConstructorParamTypes { c2.newInstance(new Object[] {"abc", Integer.valueOf(42)}); c3.newInstance(new Object[] {new int[]{42, 23}, Arrays.asList("x", "y")}); - c1.newInstance(a2); - c2.newInstance(a3); - c3.newInstance(a1); + c1.newInstance(a2); + c2.newInstance(a3); + c3.newInstance(a1); c1.newInstance(new Object[]{"42", "abc"}); c2.newInstance(new Object[]{42, 23}); @@ -46,9 +47,18 @@ class ConstructorParamTypes { cls.getConstructor(String[].class).newInstance((Object)new String[] {"abc"}); cls.getConstructor(String[].class).newInstance(new String[] {"abc"}); + + Constructor c4 = cls.getConstructor(Cloneable.class); + Constructor c5 = cls.getConstructor(Serializable.class); + + c4.newInstance(new C()); + c5.newInstance(new S()); + + c4.newInstance(new S()); + c5.newInstance(new C()); } - void arraySignatutre() throws Exception { + void arraySignature() throws Exception { Class cls = Test.class; Constructor c1 = cls.getConstructor(new Class[]{int.class, String.class}); @@ -73,9 +83,9 @@ class ConstructorParamTypes { c2.newInstance(new Object[] {"abc", Integer.valueOf(42)}); c3.newInstance(new Object[] {new int[]{42, 23}, Arrays.asList("x", "y")}); - c1.newInstance(a2); - c2.newInstance(a3); - c3.newInstance(a1); + c1.newInstance(a2); + c2.newInstance(a3); + c3.newInstance(a1); c1.newInstance(new Object[]{"42", "abc"}); c2.newInstance(new Object[]{42, 23}); @@ -87,6 +97,15 @@ class ConstructorParamTypes { cls.getConstructor(new Class[]{String[].class}).newInstance((Object)new String[] {"abc"}); cls.getConstructor(new Class[]{String[].class}).newInstance(new String[] {"abc"}); + + Constructor c4 = cls.getConstructor(new Class[]{Cloneable.class}); + Constructor c5 = cls.getConstructor(new Class[]{Serializable.class}); + + c4.newInstance(new C()); + c5.newInstance(new S()); + + c4.newInstance(new S()); + c5.newInstance(new C()); } void manyArguments() throws Exception { @@ -107,11 +126,38 @@ class ConstructorParamTypes { Object[] a5 = {0, (short)0, 0, 0.0f, "abc"}; m0.newInstance(a0); - m1.newInstance(a1); - m2.newInstance(a2); - m3.newInstance(a3); - m4.newInstance(a4); - m5.newInstance(a5); + m1.newInstance(a1); + m2.newInstance(a2); + m3.newInstance(a3); + m4.newInstance(a4); + m5.newInstance(a5); + } + + void arrayArguments() throws Exception { + Class cls = Test.class; + + Constructor c1 = cls.getConstructor(Object.class); + Constructor c2 = cls.getConstructor(Cloneable.class); + Constructor c3 = cls.getConstructor(Serializable.class); + + c1.newInstance((Object) new String[0]); + c2.newInstance((Object) new String[0]); + c3.newInstance((Object) new String[0]); + + c1.newInstance((Object) new String[][]{ new String[0] }); + c2.newInstance((Object) new String[][]{ new String[0] }); + c3.newInstance((Object) new String[][]{ new String[0] }); + + Constructor c4 = cls.getConstructor(Object[].class); + Constructor c5 = cls.getConstructor(String[].class); + + c4.newInstance((Object) new String[0]); + c4.newInstance((Object) new String[][]{ new String[0] }); + + c5.newInstance((Object) new String[0]); + c5.newInstance((Object) new String[][]{ new String[0] }); + c5.newInstance("abc"); + c5.newInstance(new Test(1, null)); } class Test { @@ -119,6 +165,11 @@ class ConstructorParamTypes { public Test(String s, Integer n) {} public Test(int[] n, List s) {} public Test(String[] s) {} + public Test(Object[] s) {} + + public Test(Object o) {} + public Test(Cloneable c) {} + public Test(Serializable s) {} } class M { @@ -128,4 +179,10 @@ class ConstructorParamTypes { public String m4(int a1, short a2, long a3, float a4) {return "";} public String m5(int a1, short a2, long a3, float a4, double a5) {return "";} } + + static class S implements Serializable { + } + + static class C implements Cloneable { + } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/javaReflectionInvocation/MethodParamTypes.java b/java/java-tests/testData/inspection/javaReflectionInvocation/MethodParamTypes.java index 261998ff30f4..836102c0de47 100644 --- a/java/java-tests/testData/inspection/javaReflectionInvocation/MethodParamTypes.java +++ b/java/java-tests/testData/inspection/javaReflectionInvocation/MethodParamTypes.java @@ -1,3 +1,4 @@ +import java.io.Serializable; import java.lang.reflect.Method; import java.util.*; @@ -33,9 +34,9 @@ class MethodParamTypes { m2.invoke(obj, new Object[] {"abc", Integer.valueOf(42)}); m3.invoke(obj, new Object[] {new int[]{42, 23}, Arrays.asList("x", "y")}); - m1.invoke(obj, a2); - m2.invoke(obj, a3); - m3.invoke(obj, a1); + m1.invoke(obj, a2); + m2.invoke(obj, a3); + m3.invoke(obj, a1); m1.invoke(obj, new Object[]{"42", "abc"}); m2.invoke(obj, new Object[]{42, 23}); @@ -47,9 +48,18 @@ class MethodParamTypes { cls.getMethod("str", String[].class).invoke(null, (Object)new String[] {"abc"}); cls.getMethod("str", String[].class).invoke(null, new String[] {"abc"}); + + Method m4 = cls.getMethod("obj", Cloneable.class); + Method m5 = cls.getMethod("obj", Serializable.class); + + m4.invoke(obj, new C()); + m5.invoke(obj, new S()); + + m4.invoke(obj, new S()); + m5.invoke(obj, new C()); } - void arraySignatutre() throws Exception { + void arraySignature() throws Exception { Class cls = Test.class; Object obj = new Test(); @@ -75,9 +85,9 @@ class MethodParamTypes { m2.invoke(obj, new Object[] {"abc", Integer.valueOf(42)}); m3.invoke(obj, new Object[] {new int[]{42, 23}, Arrays.asList("x", "y")}); - m1.invoke(obj, a2); - m2.invoke(obj, a3); - m3.invoke(obj, a1); + m1.invoke(obj, a2); + m2.invoke(obj, a3); + m3.invoke(obj, a1); m1.invoke(obj, new Object[]{"42", "abc"}); m2.invoke(obj, new Object[]{42, 23}); @@ -89,6 +99,15 @@ class MethodParamTypes { cls.getMethod("str", new Class[]{String[].class}).invoke(null, (Object)new String[] {"abc"}); cls.getMethod("str", new Class[]{String[].class}).invoke(null, new String[] {"abc"}); + + Method m4 = cls.getMethod("obj", new Class[]{Cloneable.class}); + Method m5 = cls.getMethod("obj", new Class[]{Serializable.class}); + + m4.invoke(obj, new C()); + m5.invoke(obj, new S()); + + m4.invoke(obj, new S()); + m5.invoke(obj, new C()); } void manyArguments() throws Exception { @@ -110,11 +129,39 @@ class MethodParamTypes { Object[] a5 = {0, (short)0, 0, 0.0f, "abc"}; m0.invoke(obj, a0); - m1.invoke(obj, a1); - m2.invoke(obj, a2); - m3.invoke(obj, a3); - m4.invoke(obj, a4); - m5.invoke(obj, a5); + m1.invoke(obj, a1); + m2.invoke(obj, a2); + m3.invoke(obj, a3); + m4.invoke(obj, a4); + m5.invoke(obj, a5); + } + + void arrayArguments() throws Exception { + Class cls = Test.class; + Object obj = new Test(); + + Method m1 = cls.getMethod("obj", Object.class); + Method m2 = cls.getMethod("obj", Cloneable.class); + Method m3 = cls.getMethod("obj", Serializable.class); + + m1.invoke(obj, (Object) new String[0]); + m2.invoke(obj, (Object) new String[0]); + m3.invoke(obj, (Object) new String[0]); + + m1.invoke(obj, (Object) new String[][]{ new String[0] }); + m2.invoke(obj, (Object) new String[][]{ new String[0] }); + m3.invoke(obj, (Object) new String[][]{ new String[0] }); + + Method m4 = cls.getMethod("array", Object[].class); + Method m5 = cls.getMethod("array", String[].class); + + m4.invoke(null, (Object) new String[0]); + m4.invoke(null, (Object) new String[][]{ new String[0] }); + + m5.invoke(null, (Object) new String[0]); + m5.invoke(null, (Object) new String[][]{ new String[0] }); + m5.invoke(null, "abc"); + m5.invoke(null, obj); } static class Test { @@ -123,6 +170,13 @@ class MethodParamTypes { public void bar(int[] n, List s) {} public static void str(String[] s) {} + + public void obj(Object o) {} + public void obj(Cloneable c) {} + public void obj(Serializable s) {} + + public static void array(Object[] a) {} + public static void array(String[] a) {} } class M { @@ -132,4 +186,10 @@ class MethodParamTypes { public String m4(int a1, short a2, long a3, float a4) {return "";} public String m5(int a1, short a2, long a3, float a4, double a5) {return "";} } + + static class S implements Serializable { + } + + static class C implements Cloneable { + } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/redundantCast/lambda/CastInMultidimensionalArrayIndex.java b/java/java-tests/testData/inspection/redundantCast/lambda/CastInMultidimensionalArrayIndex.java new file mode 100644 index 000000000000..5e6a9c5471c0 --- /dev/null +++ b/java/java-tests/testData/inspection/redundantCast/lambda/CastInMultidimensionalArrayIndex.java @@ -0,0 +1,5 @@ +class MyTest { + void bar(Object[] update, Object[][] grid){ + grid[(int)update[0]][1] = null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedReturnValue/quickFix/NoChangeForImplicitRead.java b/java/java-tests/testData/inspection/unusedReturnValue/quickFix/NoChangeForImplicitRead.java new file mode 100644 index 000000000000..3b544339d2ac --- /dev/null +++ b/java/java-tests/testData/inspection/unusedReturnValue/quickFix/NoChangeForImplicitRead.java @@ -0,0 +1,9 @@ +class Test { + public String implicitRead() { + return ""; + } + + { + implicitRead(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/constructor/MyServiceImpl.java b/java/java-tests/testData/inspection/unusedServiceImplementations/constructor/MyServiceImpl.java new file mode 100644 index 000000000000..2a507686b86f --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/constructor/MyServiceImpl.java @@ -0,0 +1,8 @@ +package my.impl; +import my.api.MyService; + +public class MyServiceImpl implements MyService { + public MyServiceImpl() {} + @Override + public void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/constructor/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/constructor/expected.xml new file mode 100644 index 000000000000..5e933496b9cf --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/constructor/expected.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/externalConstructor/MyServiceExt.java b/java/java-tests/testData/inspection/unusedServiceImplementations/externalConstructor/MyServiceExt.java new file mode 100644 index 000000000000..411a9b013a77 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/externalConstructor/MyServiceExt.java @@ -0,0 +1,8 @@ +package my.ext; +import my.api.MyService; + +public class MyServiceExt implements MyService { + public MyServiceExt() {} + @Override + public void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/externalConstructor/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/externalConstructor/expected.xml new file mode 100644 index 000000000000..5e933496b9cf --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/externalConstructor/expected.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/externalImplementation/MyServiceExt.java b/java/java-tests/testData/inspection/unusedServiceImplementations/externalImplementation/MyServiceExt.java new file mode 100644 index 000000000000..411a9b013a77 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/externalImplementation/MyServiceExt.java @@ -0,0 +1,8 @@ +package my.ext; +import my.api.MyService; + +public class MyServiceExt implements MyService { + public MyServiceExt() {} + @Override + public void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/externalImplementation/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/externalImplementation/expected.xml new file mode 100644 index 000000000000..5e933496b9cf --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/externalImplementation/expected.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/externalProvider/MyServiceExt.java b/java/java-tests/testData/inspection/unusedServiceImplementations/externalProvider/MyServiceExt.java new file mode 100644 index 000000000000..9f707509eee3 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/externalProvider/MyServiceExt.java @@ -0,0 +1,12 @@ +package my.ext; +import my.api.MyService; + +public class MyServiceExt { + public static MyService provider() { + return new MyService() { + @Override + public void foo() { + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/externalProvider/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/externalProvider/expected.xml new file mode 100644 index 000000000000..5e933496b9cf --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/externalProvider/expected.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/implementation/MyServiceImpl.java b/java/java-tests/testData/inspection/unusedServiceImplementations/implementation/MyServiceImpl.java new file mode 100644 index 000000000000..0a3d1e4a0b63 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/implementation/MyServiceImpl.java @@ -0,0 +1,7 @@ +package my.impl; +import my.api.MyService; + +public class MyServiceImpl implements MyService { + @Override + public void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/implementation/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/implementation/expected.xml new file mode 100644 index 000000000000..5e933496b9cf --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/implementation/expected.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/provider/MyServiceImpl.java b/java/java-tests/testData/inspection/unusedServiceImplementations/provider/MyServiceImpl.java new file mode 100644 index 000000000000..0dcb7e99ce79 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/provider/MyServiceImpl.java @@ -0,0 +1,12 @@ +package my.impl; +import my.api.MyService; + +public class MyServiceImpl { + public static MyService provider() { + return new MyService() { + @Override + public void foo() { + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/provider/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/provider/expected.xml new file mode 100644 index 000000000000..5e933496b9cf --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/provider/expected.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedConstructor/MyServiceImpl.java b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedConstructor/MyServiceImpl.java new file mode 100644 index 000000000000..2a507686b86f --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedConstructor/MyServiceImpl.java @@ -0,0 +1,8 @@ +package my.impl; +import my.api.MyService; + +public class MyServiceImpl implements MyService { + public MyServiceImpl() {} + @Override + public void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedConstructor/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedConstructor/expected.xml new file mode 100644 index 000000000000..ebefeeadcca9 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedConstructor/expected.xml @@ -0,0 +1,38 @@ + + + + MyServiceImpl.java + 5 + my.impl + + unused declaration + Constructor has usage(s) but they all belong to calls chain that has no members reachable from entry points. + + + + MyServiceImpl.java + 4 + my.impl + + unused declaration + Class has one instantiation but it is not reachable from entry points. + + + + MyService.java + 1 + my.api + + unused declaration + <ul><li>Method owner class is never instantiated OR</li><li>An instantiation is not reachable from entry points.</li></ul> + + + + MyService.java + 1 + my.api + + unused declaration + &nbsp;Interface has an implementation but <ul><li>it is never instantiated OR</li><li>no instantiations are reachable from entry points.</li></ul> + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalConstructor/MyServiceExt.java b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalConstructor/MyServiceExt.java new file mode 100644 index 000000000000..411a9b013a77 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalConstructor/MyServiceExt.java @@ -0,0 +1,8 @@ +package my.ext; +import my.api.MyService; + +public class MyServiceExt implements MyService { + public MyServiceExt() {} + @Override + public void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalConstructor/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalConstructor/expected.xml new file mode 100644 index 000000000000..decf67e8deb8 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalConstructor/expected.xml @@ -0,0 +1,38 @@ + + + + MyServiceExt.java + 5 + my.ext + + unused declaration + Constructor has usage(s) but they all belong to calls chain that has no members reachable from entry points. + + + + MyServiceExt.java + 4 + my.ext + + unused declaration + Class has one instantiation but it is not reachable from entry points. + + + + MyService.java + 1 + my.api + + unused declaration + <ul><li>Method owner class is never instantiated OR</li><li>An instantiation is not reachable from entry points.</li></ul> + + + + MyService.java + 1 + my.api + + unused declaration + &nbsp;Interface has an implementation but <ul><li>it is never instantiated OR</li><li>no instantiations are reachable from entry points.</li></ul> + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalImplementation/MyServiceExt.java b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalImplementation/MyServiceExt.java new file mode 100644 index 000000000000..443a299451f9 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalImplementation/MyServiceExt.java @@ -0,0 +1,7 @@ +package my.ext; +import my.api.MyService; + +public class MyServiceExt implements MyService { + @Override + public void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalImplementation/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalImplementation/expected.xml new file mode 100644 index 000000000000..07e39458ded6 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalImplementation/expected.xml @@ -0,0 +1,38 @@ + + + + MyServiceExt.java + 4 + my.ext + + unused declaration + Class has one instantiation but it is not reachable from entry points. + + + + MyServiceExt.java + 4 + my.ext + + unused declaration + Class has one instantiation but it is not reachable from entry points. + + + + MyService.java + 1 + my.api + + unused declaration + <ul><li>Method owner class is never instantiated OR</li><li>An instantiation is not reachable from entry points.</li></ul> + + + + MyService.java + 1 + my.api + + unused declaration + &nbsp;Interface has an implementation but <ul><li>it is never instantiated OR</li><li>no instantiations are reachable from entry points.</li></ul> + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalProvider/MyServiceExt.java b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalProvider/MyServiceExt.java new file mode 100644 index 000000000000..9f707509eee3 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalProvider/MyServiceExt.java @@ -0,0 +1,12 @@ +package my.ext; +import my.api.MyService; + +public class MyServiceExt { + public static MyService provider() { + return new MyService() { + @Override + public void foo() { + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalProvider/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalProvider/expected.xml new file mode 100644 index 000000000000..c62bfe4b7c88 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedExternalProvider/expected.xml @@ -0,0 +1,29 @@ + + + + MyServiceExt.java + 5 + my.ext + + unused declaration + Method has one usage but it is not reachable from entry points. + + + + MyService.java + 1 + my.api + + unused declaration + <ul><li>Method owner class is never instantiated OR</li><li>An instantiation is not reachable from entry points.</li></ul> + + + + MyService.java + 1 + my.api + + unused declaration + &nbsp;Interface has an implementation but <ul><li>it is never instantiated OR</li><li>no instantiations are reachable from entry points.</li></ul> + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedImplementation/MyServiceImpl.java b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedImplementation/MyServiceImpl.java new file mode 100644 index 000000000000..0a3d1e4a0b63 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedImplementation/MyServiceImpl.java @@ -0,0 +1,7 @@ +package my.impl; +import my.api.MyService; + +public class MyServiceImpl implements MyService { + @Override + public void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedImplementation/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedImplementation/expected.xml new file mode 100644 index 000000000000..c01808e2552f --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedImplementation/expected.xml @@ -0,0 +1,38 @@ + + + + MyServiceImpl.java + 4 + my.impl + + unused declaration + Class has one instantiation but it is not reachable from entry points. + + + + MyServiceImpl.java + 4 + my.impl + + unused declaration + Class has one instantiation but it is not reachable from entry points. + + + + MyService.java + 1 + my.api + + unused declaration + &nbsp;Interface has an implementation but <ul><li>it is never instantiated OR</li><li>no instantiations are reachable from entry points.</li></ul> + + + + MyService.java + 1 + my.api + + unused declaration + <ul><li>Method owner class is never instantiated OR</li><li>An instantiation is not reachable from entry points.</li></ul> + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedProvider/MyServiceImpl.java b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedProvider/MyServiceImpl.java new file mode 100644 index 000000000000..0dcb7e99ce79 --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedProvider/MyServiceImpl.java @@ -0,0 +1,12 @@ +package my.impl; +import my.api.MyService; + +public class MyServiceImpl { + public static MyService provider() { + return new MyService() { + @Override + public void foo() { + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedProvider/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedProvider/expected.xml new file mode 100644 index 000000000000..a30bfd93dcce --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedProvider/expected.xml @@ -0,0 +1,29 @@ + + + + MyServiceImpl.java + 5 + my.impl + + unused declaration + Method has one usage but it is not reachable from entry points. + + + + MyService.java + 1 + my.api + + unused declaration + <ul><li>Method owner class is never instantiated OR</li><li>An instantiation is not reachable from entry points.</li></ul> + + + + MyService.java + 1 + my.api + + unused declaration + &nbsp;Interface has an implementation but <ul><li>it is never instantiated OR</li><li>no instantiations are reachable from entry points.</li></ul> + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedVarargConstructor/MyServiceImpl.java b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedVarargConstructor/MyServiceImpl.java new file mode 100644 index 000000000000..a4f9594fd2fe --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedVarargConstructor/MyServiceImpl.java @@ -0,0 +1,8 @@ +package my.impl; +import my.api.MyService; + +public class MyServiceImpl implements MyService { + public MyServiceImpl(Object... objects) {System.out.println(objects);} + @Override + public void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/unusedVarargConstructor/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedVarargConstructor/expected.xml new file mode 100644 index 000000000000..10fe147b5bbe --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/unusedVarargConstructor/expected.xml @@ -0,0 +1,38 @@ + + + + MyServiceImpl.java + 5 + my.impl + + unused declaration + Constructor has usage(s) but they all belong to calls chain that has no members reachable from entry points. + + + + MyServiceImpl.java + 4 + my.impl + + unused declaration + Class has one instantiation but it is not reachable from entry points. + + + + MyService.java + 1 + my.api + + unused declaration + <ul><li>Method owner class is never instantiated OR</li><li>An instantiation is not reachable from entry points.</li></ul> + + + + MyService.java + 1 + my.api + + unused declaration + &nbsp;Interface has an implementation but <ul><li>it is never instantiated OR</li><li>no instantiations are reachable from entry points.</li></ul> + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/varargConstructor/MyServiceImpl.java b/java/java-tests/testData/inspection/unusedServiceImplementations/varargConstructor/MyServiceImpl.java new file mode 100644 index 000000000000..a4f9594fd2fe --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/varargConstructor/MyServiceImpl.java @@ -0,0 +1,8 @@ +package my.impl; +import my.api.MyService; + +public class MyServiceImpl implements MyService { + public MyServiceImpl(Object... objects) {System.out.println(objects);} + @Override + public void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unusedServiceImplementations/varargConstructor/expected.xml b/java/java-tests/testData/inspection/unusedServiceImplementations/varargConstructor/expected.xml new file mode 100644 index 000000000000..5e933496b9cf --- /dev/null +++ b/java/java-tests/testData/inspection/unusedServiceImplementations/varargConstructor/expected.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/convertToInstance8Method/ConvertToInstanceMethodOfTheSameClass.java b/java/java-tests/testData/refactoring/convertToInstance8Method/ConvertToInstanceMethodOfTheSameClass.java new file mode 100644 index 000000000000..620832bdc25c --- /dev/null +++ b/java/java-tests/testData/refactoring/convertToInstance8Method/ConvertToInstanceMethodOfTheSameClass.java @@ -0,0 +1,26 @@ + +class Bar { + static void foo() { + } + + void m(){ + Bar.foo(); + } + + { + Runnable r = Bar::foo; + } + + static { + Runnable r = Bar::foo; + } +} + +class Bar1 { + void m() { + Bar.foo(); + } + { + Runnable r = Bar::foo; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/convertToInstance8Method/ConvertToInstanceMethodOfTheSameClass.java.after b/java/java-tests/testData/refactoring/convertToInstance8Method/ConvertToInstanceMethodOfTheSameClass.java.after new file mode 100644 index 000000000000..2167412c087b --- /dev/null +++ b/java/java-tests/testData/refactoring/convertToInstance8Method/ConvertToInstanceMethodOfTheSameClass.java.after @@ -0,0 +1,26 @@ + +class Bar { + void foo() { + } + + void m(){ + foo(); + } + + { + Runnable r = this::foo; + } + + static { + Runnable r = new Bar()::foo; + } +} + +class Bar1 { + void m() { + new Bar().foo(); + } + { + Runnable r = new Bar()::foo; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/convertToInstance8Method/ConvertToInstanceMethodOfTheSameClassWithTypeParams.java b/java/java-tests/testData/refactoring/convertToInstance8Method/ConvertToInstanceMethodOfTheSameClassWithTypeParams.java new file mode 100644 index 000000000000..93a77ddd0f6b --- /dev/null +++ b/java/java-tests/testData/refactoring/convertToInstance8Method/ConvertToInstanceMethodOfTheSameClassWithTypeParams.java @@ -0,0 +1,26 @@ + +class Bar { + static void foo() { + } + + void m(){ + Bar.foo(); + } + + { + Runnable r = Bar::foo; + } + + static { + Runnable r = Bar::foo; + } +} + +class Bar1 { + void m() { + Bar.foo(); + } + { + Runnable r = Bar::foo; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/convertToInstance8Method/MethodReferenceAcceptableBySecondSearch.java b/java/java-tests/testData/refactoring/convertToInstance8Method/MethodReferenceAcceptableBySecondSearch.java new file mode 100644 index 000000000000..f74b6b09f393 --- /dev/null +++ b/java/java-tests/testData/refactoring/convertToInstance8Method/MethodReferenceAcceptableBySecondSearch.java @@ -0,0 +1,11 @@ +class Bar0 {} +class Bar { + void f() { + I r = Bar::foo; + } + + private static void foo(Bar0 bar) { } +} +interface I { + void m(Bar0 b); +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/convertToInstance8Method/MethodReferenceAcceptableBySecondSearch.java.after b/java/java-tests/testData/refactoring/convertToInstance8Method/MethodReferenceAcceptableBySecondSearch.java.after new file mode 100644 index 000000000000..611da468d055 --- /dev/null +++ b/java/java-tests/testData/refactoring/convertToInstance8Method/MethodReferenceAcceptableBySecondSearch.java.after @@ -0,0 +1,12 @@ +class Bar0 { + void foo() { } +} +class Bar { + void f() { + I r = Bar0::foo; + } + +} +interface I { + void m(Bar0 b); +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/convertToInstance8Method/MethodReferenceToLambda.java b/java/java-tests/testData/refactoring/convertToInstance8Method/MethodReferenceToLambda.java new file mode 100644 index 000000000000..3a3fa88827f7 --- /dev/null +++ b/java/java-tests/testData/refactoring/convertToInstance8Method/MethodReferenceToLambda.java @@ -0,0 +1,11 @@ +class Bar0 {} +class Bar { + void f() { + I r = Bar::foo; + } + + private static void foo(Integer i, Bar0 bar) { } +} +interface I { + void m(Integer i, Bar0 b); +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/convertToInstance8Method/MethodReferenceToLambda.java.after b/java/java-tests/testData/refactoring/convertToInstance8Method/MethodReferenceToLambda.java.after new file mode 100644 index 000000000000..208b9fe174ab --- /dev/null +++ b/java/java-tests/testData/refactoring/convertToInstance8Method/MethodReferenceToLambda.java.after @@ -0,0 +1,12 @@ +class Bar0 { + void foo(Integer i) { } +} +class Bar { + void f() { + I r = (i, bar) -> bar.foo(i); + } + +} +interface I { + void m(Integer i, Bar0 b); +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/convertToInstance8Method/ThisInsteadOfNoQualifier.java b/java/java-tests/testData/refactoring/convertToInstance8Method/ThisInsteadOfNoQualifier.java new file mode 100644 index 000000000000..b8092970b418 --- /dev/null +++ b/java/java-tests/testData/refactoring/convertToInstance8Method/ThisInsteadOfNoQualifier.java @@ -0,0 +1,8 @@ +class Bar { + void f() {} + + private static void foo(Bar bar) { + bar.f(); + Runnable r = bar::f; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/convertToInstance8Method/ThisInsteadOfNoQualifier.java.after b/java/java-tests/testData/refactoring/convertToInstance8Method/ThisInsteadOfNoQualifier.java.after new file mode 100644 index 000000000000..60eabdeccec6 --- /dev/null +++ b/java/java-tests/testData/refactoring/convertToInstance8Method/ThisInsteadOfNoQualifier.java.after @@ -0,0 +1,9 @@ +class Bar { + private void foo() { + f(); + Runnable r = this::f; + } + + void f() {} + +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/moveInstanceMethod/MethodReference.java.after b/java/java-tests/testData/refactoring/moveInstanceMethod/MethodReference.java.after new file mode 100644 index 000000000000..fe6abb330a88 --- /dev/null +++ b/java/java-tests/testData/refactoring/moveInstanceMethod/MethodReference.java.after @@ -0,0 +1,17 @@ +interface SAM { + String m(MethodReference f, F f1); +} + + +class F { + String getX() { + return null; + } +} + +class MethodReference { + + static void test() { + SAM s = (stringMethodReference, f1) -> f1.getX(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/moveInstanceMethod/MethodReferenceToExpandToLambda.java b/java/java-tests/testData/refactoring/moveInstanceMethod/MethodReferenceToExpandToLambda.java new file mode 100644 index 000000000000..941e2e0fea5e --- /dev/null +++ b/java/java-tests/testData/refactoring/moveInstanceMethod/MethodReferenceToExpandToLambda.java @@ -0,0 +1,17 @@ + +class Bar { + void foo(int i, Bar1 b1) { + } + +} + +class Bar1 { + + void m(Bar b) { + Bar3 r = b::foo; + } +} + +interface Bar3 { + void m(int i, Bar1 v); +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/moveInstanceMethod/MethodReferenceToExpandToLambda.java.after b/java/java-tests/testData/refactoring/moveInstanceMethod/MethodReferenceToExpandToLambda.java.after new file mode 100644 index 000000000000..6fce2de54dcb --- /dev/null +++ b/java/java-tests/testData/refactoring/moveInstanceMethod/MethodReferenceToExpandToLambda.java.after @@ -0,0 +1,18 @@ + +class Bar { + +} + +class Bar1 { + + void m(Bar b) { + Bar3 r = (i, b1) -> b1.foo(i); + } + + void foo(int i) { + } +} + +interface Bar3 { + void m(int i, Bar1 v); +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/moveInstanceMethod/ParameterMethodReference.java.after b/java/java-tests/testData/refactoring/moveInstanceMethod/ParameterMethodReference.java.after index 61ff4a019980..1e2897d7db28 100644 --- a/java/java-tests/testData/refactoring/moveInstanceMethod/ParameterMethodReference.java.after +++ b/java/java-tests/testData/refactoring/moveInstanceMethod/ParameterMethodReference.java.after @@ -10,7 +10,7 @@ class Test { private final Destination destination = new Destination(); public void main(Stream stream){ - stream.filter(Test.Destination::notNull); + stream.filter(Destination::notNull); } } \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/after/b/B.java b/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/after/b/B.java new file mode 100644 index 000000000000..d6457aef6e16 --- /dev/null +++ b/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/after/b/B.java @@ -0,0 +1,6 @@ +package b; + +import b.a.A; +public class B { + A aa; +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/after/b/C.java b/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/after/b/C.java new file mode 100644 index 000000000000..beba5243f562 --- /dev/null +++ b/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/after/b/C.java @@ -0,0 +1,2 @@ +package b; +class C {} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/after/b/a/A.java b/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/after/b/a/A.java new file mode 100644 index 000000000000..4cc1ad36b90a --- /dev/null +++ b/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/after/b/a/A.java @@ -0,0 +1,2 @@ +package b.a; +public class A {} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/before/B.java b/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/before/B.java new file mode 100644 index 000000000000..a17e968da5fa --- /dev/null +++ b/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/before/B.java @@ -0,0 +1,4 @@ +import a.A; +public class B { + A aa; +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/before/a/A.java b/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/before/a/A.java new file mode 100644 index 000000000000..c40d43155dc2 --- /dev/null +++ b/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/before/a/A.java @@ -0,0 +1,2 @@ +package a; +public class A {} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/before/b/C.java b/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/before/b/C.java new file mode 100644 index 000000000000..beba5243f562 --- /dev/null +++ b/java/java-tests/testData/refactoring/movePackage/packageAndReferencedClass/before/b/C.java @@ -0,0 +1,2 @@ +package b; +class C {} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy index e24e151ffb81..47538a326834 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy @@ -138,7 +138,7 @@ class Bar {{ abcmethod(); anotherMethod() }}""" } """) - JavaProjectCodeInsightSettings.setExcludedNames(project, myFixture.testRootDisposable, "foo.Excl") + JavaProjectCodeInsightSettings.setExcludedNames(project, myFixture.testRootDisposable, "*Excl") doTest "class Bar {{ abcm }}", true, """import static foo.Foo.abcmethod; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt index 662ee8c280a9..52dd549f2935 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt @@ -55,6 +55,11 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() { highlight("""module M { }""") } + fun testFileDuplicateInTestRoot() { + addTestFile("module-info.java", """module M.test { }""") + highlight("""module M { }""") + } + fun testWrongFileLocation() { highlight("pkg/module-info.java", """module M { }""") } @@ -241,6 +246,80 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() { """.trimIndent()) } + fun testPackageAccessibilityInNonModularTest() { + addFile("module-info.java", "module M { }") + addFile("module-info.java", "module M2 { exports pkg.m2; exports pkg.m2.impl to close.friends.only; }", M2) + addFile("pkg/m2/C2.java", "package pkg.m2;\npublic class C2 { }", M2) + addFile("pkg/m2/impl/C2Impl.java", "package pkg.m2.impl;\nimport pkg.m2.C2;\npublic class C2Impl { public static C2 make() {} }", M2) + addFile("pkg/m4/C4.java", "package pkg.m4;\npublic class C4 { }", M4) + addFile("module-info.java", "module M5 { exports pkg.m5; }", M5) + addFile("pkg/m5/C5.java", "package pkg.m5;\npublic class C5 { }", M5) + addFile("module-info.java", "module M6 { requires transitive M7; }", M6) + addFile("module-info.java", "module M7 { exports pkg.m7; }", M7) + addFile("pkg/m7/C7.java", "package pkg.m7;\npublic class C7 { }", M7) + highlight("test.java", """ + import pkg.m2.C2; + import pkg.m2.*; + import pkg.m2.impl.C2Impl; + import pkg.m2.impl.*; + import pkg.m4.C4; + import pkg.m5.C5; + import pkg.m7.C7; + + import pkg.lib1.LC1; + import pkg.lib1.impl.LC1Impl; + import pkg.lib1.impl.*; + + import pkg.lib2.LC2; + import pkg.lib2.impl.LC2Impl; + + import static pkg.m2.impl.C2Impl.make; + + /** See also {@link C2Impl#make} */ + class C {{ + C2Impl.make(); + pkg.m2.impl.C2Impl.make(); + }} + """.trimIndent(), true) + } + + fun testPackageAccessibilityInModularTest() { + addTestFile("module-info.java", "module M { requires M2; requires M6; requires lib.named; requires lib.auto; }") + addFile("module-info.java", "module M2 { exports pkg.m2; exports pkg.m2.impl to close.friends.only; }", M2) + addFile("pkg/m2/C2.java", "package pkg.m2;\npublic class C2 { }", M2) + addFile("pkg/m2/impl/C2Impl.java", "package pkg.m2.impl;\nimport pkg.m2.C2;\npublic class C2Impl { public static C2 make() {} }", M2) + addFile("pkg/m4/C4.java", "package pkg.m4;\npublic class C4 { }", M4) + addFile("module-info.java", "module M5 { exports pkg.m5; }", M5) + addFile("pkg/m5/C5.java", "package pkg.m5;\npublic class C5 { }", M5) + addFile("module-info.java", "module M6 { requires transitive M7; }", M6) + addFile("module-info.java", "module M7 { exports pkg.m7; }", M7) + addFile("pkg/m7/C7.java", "package pkg.m7;\npublic class C7 { }", M7) + highlight("test.java", """ + import pkg.m2.C2; + import pkg.m2.*; + import pkg.m2.impl.C2Impl; + import pkg.m2.impl.*; + import pkg.m4.C4; + import pkg.m5.C5; + import pkg.m7.C7; + + import pkg.lib1.LC1; + import pkg.lib1.impl.LC1Impl; + import pkg.lib1.impl.*; + + import pkg.lib2.LC2; + import pkg.lib2.impl.LC2Impl; + + import static pkg.m2.impl.C2Impl.make; + + /** See also {@link C2Impl#make} */ + class C {{ + C2Impl.make(); + pkg.m2.impl.C2Impl.make(); + }} + """.trimIndent(), true) + } + fun testLinearModuleGraphBug() { addFile("module-info.java", "module M6 { requires M7; }", M6) addFile("module-info.java", "module M7 { }", M7) @@ -303,8 +382,8 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() { // private fun highlight(text: String) = highlight("module-info.java", text) - private fun highlight(path: String, text: String) { - myFixture.configureFromExistingVirtualFile(addFile(path, text)) + private fun highlight(path: String, text: String, isTest: Boolean = false) { + myFixture.configureFromExistingVirtualFile(if (isTest) addTestFile(path, text) else addFile(path, text)) myFixture.checkHighlighting() } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/RecursiveVisitorTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/RecursiveVisitorTest.java index fcdc8eea5a01..cb24d80bf180 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/RecursiveVisitorTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/RecursiveVisitorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,14 @@ package com.intellij.codeInsight.daemon; import com.intellij.psi.*; import com.intellij.testFramework.PlatformTestUtil; +import com.intellij.testFramework.SkipSlowTestLocally; import com.intellij.util.IncorrectOperationException; import com.intellij.util.ThrowableRunnable; /** * @author cdr */ +@SkipSlowTestLocally public class RecursiveVisitorTest extends LightDaemonAnalyzerTestCase{ public void testHugeConcatenationVisitingPerformance() throws IncorrectOperationException { StringBuilder text = new StringBuilder("String s = null"); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/DaemonRespondToChangesTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/DaemonRespondToChangesTest.java index f3e88757e689..c03d1d073ddc 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/DaemonRespondToChangesTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/DaemonRespondToChangesTest.java @@ -15,12 +15,14 @@ */ package com.intellij.codeInsight.daemon.impl; +import com.intellij.application.options.editor.CodeFoldingConfigurable; import com.intellij.codeHighlighting.*; import com.intellij.codeInsight.EditorInfo; import com.intellij.codeInsight.completion.CompletionContributor; import com.intellij.codeInsight.daemon.*; import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase; import com.intellij.codeInsight.folding.CodeFoldingManager; +import com.intellij.codeInsight.folding.JavaCodeFoldingSettings; import com.intellij.codeInsight.hint.EditorHintListener; import com.intellij.codeInsight.intention.AbstractIntentionAction; import com.intellij.codeInsight.intention.IntentionAction; @@ -2158,7 +2160,7 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase { private volatile boolean runHeavyProcessing; public void testDaemonDisablesItselfDuringHeavyProcessing() throws Exception { - executeWithReparseDelay(() -> { + executeWithoutReparseDelay(() -> { runHeavyProcessing = false; try { final Set applied = Collections.synchronizedSet(new THashSet<>()); @@ -2380,7 +2382,7 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase { makeEditorWindowVisible(new Point(0, 0), myEditor); doHighlighting(); myDaemonCodeAnalyzer.restart(); - executeWithReparseDelay(() -> { + executeWithoutReparseDelay(() -> { for (int i = 0; i < 1000; i++) { caretRight(); UIUtil.dispatchAllInvocationEvents(); @@ -2397,7 +2399,7 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase { }); } - private static void executeWithReparseDelay(@NotNull Runnable task) { + private static void executeWithoutReparseDelay(@NotNull Runnable task) { DaemonCodeAnalyzerSettings settings = DaemonCodeAnalyzerSettings.getInstance(); int oldDelay = settings.AUTOREPARSE_DELAY; settings.AUTOREPARSE_DELAY = 0; @@ -2441,8 +2443,7 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase { } public void testCodeFoldingPassRestartsOnRegionUnfolding() throws Exception { - DaemonCodeAnalyzerSettings settings = DaemonCodeAnalyzerSettings.getInstance(); - executeWithReparseDelay(() -> { + executeWithoutReparseDelay(() -> { configureByText(StdFileTypes.JAVA, "class Foo {\n" + " void m() {\n" + "\n" + @@ -2469,6 +2470,30 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase { }); } + public void testChangingSettingsHasImmediateEffectOnOpenedEditor() throws Exception { + executeWithoutReparseDelay(() -> { + configureByText(StdFileTypes.JAVA, "class C { \n" + + " void m() {\n" + + " } \n" + + "}"); + CodeFoldingManager.getInstance(getProject()).buildInitialFoldings(myEditor); + waitForDaemon(); + checkFoldingState("[FoldRegion -(22:27), placeholder='{}']"); + + JavaCodeFoldingSettings settings = JavaCodeFoldingSettings.getInstance(); + boolean savedValue = settings.isCollapseMethods(); + try { + settings.setCollapseMethods(true); + CodeFoldingConfigurable.applyCodeFoldingSettingsChanges(); + waitForDaemon(); + checkFoldingState("[FoldRegion +(22:27), placeholder='{}']"); + } + finally { + settings.setCollapseMethods(savedValue); + } + }); + } + private void checkFoldingState(String expected) { assertEquals(expected, Arrays.toString(myEditor.getFoldingModel().getAllFoldRegions())); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java index bf3d4c349a7e..50ae8601fd14 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java @@ -178,6 +178,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase doTest(); } + public void testTopLevelParentNoParameters() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/MergeModuleStatementsFixTest.kt b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/MergeModuleStatementsFixTest.kt index 6bc714d33279..1a8bf9b589a4 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/MergeModuleStatementsFixTest.kt +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/MergeModuleStatementsFixTest.kt @@ -17,7 +17,6 @@ package com.intellij.codeInsight.daemon.quickFix import com.intellij.JavaTestUtil.getRelativeJavaTestDataPath import com.intellij.codeInsight.daemon.QuickFixBundle -import com.intellij.codeInsight.intention.IntentionAction import com.intellij.testFramework.fixtures.LightJava9ModulesCodeInsightFixtureTestCase import com.intellij.testFramework.fixtures.MultiModuleJava9ProjectDescriptor.ModuleDescriptor.* @@ -29,14 +28,14 @@ class MergeModuleStatementsFixTest : LightJava9ModulesCodeInsightFixtureTestCase override fun getBasePath() = getRelativeJavaTestDataPath() + "/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix" fun testExports1() = doTest("exports", "my.api") - fun testExports2() = doTest("exports", "my.api") + fun testExports2() = doTest("exports", "my.api", false) fun testProvides1() = doTest("provides", "my.api.MyService") fun testProvides2() = doTest("provides", "my.api.MyService") fun testProvides3() = doTest("provides", "my.api.MyService") fun testOpens1() = doTest("opens", "my.api") - fun testOpens2() = doTest("opens", "my.api") + fun testOpens2() = doTest("opens", "my.api", false) override fun setUp() { @@ -51,22 +50,23 @@ class MergeModuleStatementsFixTest : LightJava9ModulesCodeInsightFixtureTestCase addFile("my/impl/MyServiceImpl2.java", "package my.impl; public class MyServiceImpl2 extends my.api.MyService {}") } - private fun doTest(type: String, name: String) { + private fun doTest(type: String, name: String, expected: Boolean = true) { val testName = getTestName(false) val virtualFile = myFixture.copyFileToProject("${testName}.java", "module-info.java") myFixture.configureFromExistingVirtualFile(virtualFile) - val action = findActionWithText(QuickFixBundle.message("java.9.merge.module.statements.fix.name", type, name)) + myFixture.doHighlighting() + val actions = LightQuickFixTestCase.getAvailableActions(editor, file) + val actionText = QuickFixBundle.message("java.9.merge.module.statements.fix.name", type, name) + val action = LightQuickFixTestCase.findActionWithText(actions, actionText) + + if (!expected) { + assertNull("Action \"$actionText\" is not expected", action) + return + } + + assertNotNull("No action \"$actionText\" in ${actions.map { it.text }}", action) myFixture.launchAction(action) myFixture.checkResultByFile("${testName}_after.java") } - - private fun findActionWithText(actionText: String): IntentionAction { - myFixture.doHighlighting() - - val actions = LightQuickFixTestCase.getAvailableActions(editor, file) - val action = LightQuickFixTestCase.findActionWithText(actions, actionText) - assertNotNull("No action [$actionText] in ${actions.map { it.text }}", action) - return action - } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/intention/AddImportActionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/intention/AddImportActionTest.groovy index 46402e71ee78..e60cec9f6a28 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/intention/AddImportActionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/intention/AddImportActionTest.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,10 +20,12 @@ import com.intellij.lang.java.JavaLanguage import com.intellij.pom.java.LanguageLevel import com.intellij.psi.codeStyle.CodeStyleSettings import com.intellij.psi.codeStyle.CodeStyleSettingsManager +import com.intellij.psi.codeStyle.JavaCodeStyleSettings import com.intellij.psi.statistics.StatisticsManager import com.intellij.psi.statistics.impl.StatisticsManagerImpl import com.intellij.testFramework.IdeaTestUtil import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import com.siyeh.ig.style.UnnecessaryFullyQualifiedNameInspection class AddImportActionTest extends LightCodeInsightFixtureTestCase { private CodeStyleSettings settings @@ -256,7 +258,7 @@ class C { myFixture.configureByText 'a.java', ''' class Test { - java.util.@TA Collection<@TA String> c; + java.util.@TA Collection<@TA String> c; }'''.stripIndent().trim() reimportClass() @@ -265,7 +267,7 @@ class C { import java.util.Collection; class Test { - @TA Collection<@TA String> c; + @TA Collection<@TA String> c; }'''.stripIndent().trim() } @@ -390,7 +392,7 @@ class Test { class Test { /** - * {@link java.util.Map} + * {@link java.util.Map} */ void run() { } @@ -416,13 +418,14 @@ class Test { class Test { /** - * {@link java.lang.Math} + * {@link java.lang.Math} */ void run() { } } ''' - reimportClass() + myFixture.enableInspections(new UnnecessaryFullyQualifiedNameInspection()) + myFixture.launchAction(myFixture.findSingleIntention("Remove qualification")) myFixture.checkResult ''' class Test { @@ -488,6 +491,8 @@ class Tq { void setUp() throws Exception { super.setUp() settings = new CodeStyleSettings() + JavaCodeStyleSettings javaSettings = settings.getCustomSettings(JavaCodeStyleSettings.class); + javaSettings.CLASS_NAMES_IN_JAVADOC = JavaCodeStyleSettings.SHORTEN_NAMES_ALWAYS_AND_ADD_IMPORT CodeStyleSettingsManager.getInstance(myFixture.project).setTemporarySettings(settings) } @@ -503,7 +508,8 @@ class Tq { } private def reimportClass() { - myFixture.launchAction(myFixture.findSingleIntention("Replace qualified name with 'import'")) + myFixture.enableInspections(new UnnecessaryFullyQualifiedNameInspection()) + myFixture.launchAction(myFixture.findSingleIntention("Replace with import")) } void "test disprefer deprecated classes"() { diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index 666d3e139975..8ee0a36df387 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -190,6 +190,7 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase { public void testOtherCallMayChangeFields() { doTest(); } public void testMethodCallFlushesField() { doTest(); } + public void testDoubleNaN() { doTest(); } public void testUnknownFloatMayBeNaN() { doTest(); } public void testBoxedNaN() { doTest(); } public void testFloatEquality() { doTest(); } @@ -247,6 +248,9 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase { public void testContractSeveralClauses() { doTest(); } public void testContractVarargs() { doTest(); } public void testContractConstructor() { doTest(); } + public void testFlushVariableOnStackToNotNullType() { doTest(); } + + public void testCustomContracts() { doTest(); } public void testBoxingImpliesNotNull() { doTest(); } public void testLargeIntegersAreNotEqualWhenBoxed() { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/Java9UnusedServiceImplementationsTest.kt b/java/java-tests/testSrc/com/intellij/codeInspection/Java9UnusedServiceImplementationsTest.kt new file mode 100644 index 000000000000..00279bd4ab61 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInspection/Java9UnusedServiceImplementationsTest.kt @@ -0,0 +1,118 @@ +/* + * Copyright 2000-2017 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.codeInspection + +import com.intellij.analysis.AnalysisScope +import com.intellij.openapi.application.ex.PathManagerEx +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.util.io.FileUtil +import com.intellij.testFramework.InspectionTestCase +import com.intellij.testFramework.InspectionTestUtil +import com.intellij.testFramework.createGlobalContextForTool +import com.intellij.testFramework.fixtures.LightJava9ModulesCodeInsightFixtureTestCase +import com.intellij.testFramework.fixtures.MultiModuleJava9ProjectDescriptor.ModuleDescriptor +import com.intellij.testFramework.fixtures.MultiModuleJava9ProjectDescriptor.ModuleDescriptor.* +import org.intellij.lang.annotations.Language + +/** + * @author Pavel.Dolgov + */ +class Java9UnusedServiceImplementationsTest : LightJava9ModulesCodeInsightFixtureTestCase() { + override fun getTestDataPath() = PathManagerEx.getTestDataPath() + "/inspection/unusedServiceImplementations/" + + override fun setUp() { + super.setUp() + + moduleInfo("module MAIN { requires API; }", MAIN) + + addFile("my/api/MyService.java", "package my.api; public interface MyService { void foo(); }", M2) + } + + fun testImplementation() = doTest() + + fun testConstructor() = doTest() + + fun testProvider() = doTest() + + fun testVarargConstructor() = doTest() + + fun testUnusedImplementation() = doTest(false) + + fun testUnusedConstructor() = doTest(false) + + fun testUnusedProvider() = doTest(false) + + fun testUnusedVarargConstructor() = doTest(false) + + fun testExternalImplementation() = doTest(sameModule = false) + + fun testExternalConstructor() = doTest(sameModule = false) + + fun testExternalProvider() = doTest(sameModule = false) + + fun testUnusedExternalImplementation() = doTest(false, sameModule = false) + + fun testUnusedExternalConstructor() = doTest(false, sameModule = false) + + fun testUnusedExternalProvider() = doTest(false, sameModule = false) + + + private fun doTest(withUsage: Boolean = true, sameModule: Boolean = true) { + @Language("JAVA") + val usageText = """ + import my.api.MyService; + public class MyApp { + public static void main(String[] args) { + for (MyService service : ServiceLoader.load(MyService.class)) { + service.foo(); + } + } + }""" + if (withUsage) addFile("my/app/MyApp.java", usageText, MAIN) + + if (sameModule) { + moduleInfo("module API { exports my.api; provides my.api.MyService with my.impl.MyServiceImpl; }", M2) + } + else { + val moduleManager = ModuleManager.getInstance(project) + val m2 = moduleManager.findModuleByName(M2.moduleName)!! + val m4 = moduleManager.findModuleByName(M4.moduleName)!! + ModuleRootModificationUtil.addDependency(m4, m2) + moduleInfo("module API { exports my.api; }", M2) + moduleInfo("module EXT { requires API; provides my.api.MyService with my.ext.MyServiceExt; }", M4) + } + + val testPath = testDataPath + "/" + getTestName(true) + val sourceFile = FileUtil.findFirstThatExist("$testPath/MyService${if (sameModule) "Impl" else "Ext"}.java") + assertNotNull("Test data: $testPath", sourceFile) + val implText = String(FileUtil.loadFileText(sourceFile!!)) + if (sameModule) + addFile("my/impl/MyServiceImpl.java", implText, M2) + else + addFile("my/ext/MyServiceExt.java", implText, M4) + + val toolWrapper = InspectionTestCase.getUnusedDeclarationWrapper() + val scope = AnalysisScope(project) + val globalContext = createGlobalContextForTool(scope, project, listOf(toolWrapper)) + InspectionTestUtil.runTool(toolWrapper, scope, globalContext) + InspectionTestUtil.compareToolResults(globalContext, toolWrapper, true, testPath) + } + + private fun moduleInfo(@Language("JAVA") moduleInfoText: String, descriptor: ModuleDescriptor) { + addFile("module-info.java", moduleInfoText, descriptor) + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantCast18Test.java b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantCast18Test.java index f544cfa44798..d1c48111b910 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantCast18Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantCast18Test.java @@ -41,4 +41,5 @@ public class RedundantCast18Test extends LightDaemonAnalyzerTestCase { public void testConditional() { doTest(); } public void testInferApplicabilityError() { doTest(); } public void testCastToRawType() { doTest(); } + public void testCastInMultidimensionalArrayIndex() { doTest(); } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/UnusedReturnValueQuickFixTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/UnusedReturnValueQuickFixTest.java index 7048df0f57bb..dcff2ac300c4 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/UnusedReturnValueQuickFixTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/UnusedReturnValueQuickFixTest.java @@ -16,7 +16,12 @@ package com.intellij.codeInspection; import com.intellij.JavaTestUtil; +import com.intellij.codeInsight.daemon.ImplicitUsageProvider; import com.intellij.codeInspection.unusedReturnValue.UnusedReturnValue; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; /** @@ -27,11 +32,33 @@ public class UnusedReturnValueQuickFixTest extends LightCodeInsightFixtureTestCa @Override protected void setUp() throws Exception { super.setUp(); + PlatformTestUtil.registerExtension(Extensions.getRootArea(), ImplicitUsageProvider.EP_NAME, new ImplicitUsageProvider() { + @Override + public boolean isImplicitUsage(PsiElement element) { + return false; + } + + @Override + public boolean isImplicitRead(PsiElement element) { + return element instanceof PsiMethod && ((PsiMethod)element).getName().equals("implicitRead"); + } + + @Override + public boolean isImplicitWrite(PsiElement element) { + return false; + } + }, getTestRootDisposable()); + myFixture.enableInspections(new UnusedReturnValue()); } public void testSideEffects() { doTest(); } public void testRedundantReturn() { doTest(); } + public void testNoChangeForImplicitRead() { + final String name = getTestName(false); + myFixture.configureByFile(name + ".java"); + assertEmpty(myFixture.filterAvailableIntentions(InspectionsBundle.message("inspection.unused.return.value.make.void.quickfix"))); + } private void doTest() { final String name = getTestName(false); diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSetTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSetTest.java index 1a31fcd04165..1f09379891eb 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSetTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSetTest.java @@ -15,7 +15,7 @@ */ package com.intellij.codeInspection.dataFlow.rangeSet; -import com.intellij.psi.JavaTokenType; +import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType; import com.intellij.psi.PsiType; import com.intellij.util.containers.HashMap; import org.junit.Test; @@ -241,14 +241,14 @@ public class LongRangeSetTest { @Test public void testFromRelation() { - assertEquals(range(101, Long.MAX_VALUE), range(100, 200).fromRelation(JavaTokenType.GT)); - assertEquals(range(100, Long.MAX_VALUE), range(100, 200).fromRelation(JavaTokenType.GE)); - assertEquals(range(Long.MIN_VALUE, 199), range(100, 200).fromRelation(JavaTokenType.LT)); - assertEquals(range(Long.MIN_VALUE, 200), range(100, 200).fromRelation(JavaTokenType.LE)); - assertEquals(range(100, 200), range(100, 200).fromRelation(JavaTokenType.EQEQ)); - assertNull(range(100, 200).fromRelation(JavaTokenType.EQ)); - assertEquals(fromType(PsiType.LONG), range(100, 200).fromRelation(JavaTokenType.NE)); - assertEquals("{-9223372036854775808..99, 101..9223372036854775807}", point(100).fromRelation(JavaTokenType.NE).toString()); + assertEquals(range(101, Long.MAX_VALUE), range(100, 200).fromRelation(RelationType.GT)); + assertEquals(range(100, Long.MAX_VALUE), range(100, 200).fromRelation(RelationType.GE)); + assertEquals(range(Long.MIN_VALUE, 199), range(100, 200).fromRelation(RelationType.LT)); + assertEquals(range(Long.MIN_VALUE, 200), range(100, 200).fromRelation(RelationType.LE)); + assertEquals(range(100, 200), range(100, 200).fromRelation(RelationType.EQ)); + assertNull(range(100, 200).fromRelation(RelationType.IS)); + assertEquals(fromType(PsiType.LONG), range(100, 200).fromRelation(RelationType.NE)); + assertEquals("{-9223372036854775808..99, 101..9223372036854775807}", point(100).fromRelation(RelationType.NE).toString()); } @Test diff --git a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferenceDataInCompletionTest.java b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferenceDataInCompletionTest.java index 6b009fd7157e..3df72b2fe78d 100644 --- a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferenceDataInCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferenceDataInCompletionTest.java @@ -72,6 +72,17 @@ public class CompilerReferenceDataInCompletionTest extends CompilerReferencesTes doTestConstructorCompletionOrdering(new String[] {"Foo.java"}, "List l = new ", "AbstractList", "ArrayList"); } + public void testHelperMethodIsNotAffected() { + doTestStaticMemberCompletionOrdering(new String[] {"Foo.java"}, "someMethod2(1)", "someMethod1(0)", "m(0)", "nonNull(1)"); + } + + public void testExpectedByTypeAreFirst() { + doTestCompletion(new String[] {"Foo.java"}, "String s = ", new String[] {"someMethod2(1)", "someMethod1(0)", "someMethod3(0)", "m(0)", "mm(1)"}, m -> { + PsiClass aClass = m.getContainingClass(); + return aClass != null && "Foo".equals(aClass.getName()); + }); + } + private void doTestConstructorCompletionOrdering(@NotNull String[] files, @NotNull String phraseToComplete, String... expectedOrder) { @@ -82,6 +93,13 @@ public class CompilerReferenceDataInCompletionTest extends CompilerReferencesTes doTestCompletion(files, "foo.", expectedOrder, m -> "Foo".equals(m.getContainingClass().getName())); } + private void doTestStaticMemberCompletionOrdering(@NotNull String[] files, String... expectedOrder) { + doTestCompletion(files, "", expectedOrder, (PsiMember m) -> { + PsiClass aClass = m.getContainingClass(); + return aClass != null && "Foo".equals(aClass.getName()); + }); + } + private void doTestCompletion(@NotNull String[] files, @NotNull String phraseToComplete, @NotNull String[] expectedOrder, diff --git a/java/java-tests/testSrc/com/intellij/execution/ConfigurationRefactoringsTest.java b/java/java-tests/testSrc/com/intellij/execution/ConfigurationRefactoringsTest.java index 63ed69c6369a..521b2c478285 100644 --- a/java/java-tests/testSrc/com/intellij/execution/ConfigurationRefactoringsTest.java +++ b/java/java-tests/testSrc/com/intellij/execution/ConfigurationRefactoringsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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,6 +18,7 @@ package com.intellij.execution; import com.intellij.execution.application.ApplicationConfiguration; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.configurations.RuntimeConfigurationException; +import com.intellij.execution.impl.RunManagerImpl; import com.intellij.execution.impl.RunnerAndConfigurationSettingsImpl; import com.intellij.execution.junit.AllInPackageConfigurationProducer; import com.intellij.execution.junit.JUnitConfiguration; @@ -154,7 +155,8 @@ public class ConfigurationRefactoringsTest extends BaseConfigurationTestCase { checkConfigurationException("NotATest isn't test class", configuration); - RunManagerEx.getInstanceEx(myProject).setTemporaryConfiguration(new RunnerAndConfigurationSettingsImpl(null, configuration, false)); + RunManagerImpl runManager = (RunManagerImpl)RunManagerEx.getInstanceEx(myProject); + runManager.setTemporaryConfiguration(new RunnerAndConfigurationSettingsImpl(runManager, configuration, false)); rename(psiClass, "NotATest2"); JUnitConfiguration.Data data = configuration.getPersistentData(); assertEquals("NotATest2", data.getMainClassName()); @@ -230,15 +232,20 @@ public class ConfigurationRefactoringsTest extends BaseConfigurationTestCase { @Override protected void tearDown() throws Exception { - mySource.tearDown(); - mySource = null; - super.tearDown(); + try { + mySource.tearDown(); + mySource = null; + } + finally { + super.tearDown(); + } } @Override protected T createConfiguration(@NotNull PsiElement psiClass, @NotNull MapDataContext dataContext) { T configuration = super.createConfiguration(psiClass, dataContext); - RunManagerEx.getInstanceEx(myProject).setTemporaryConfiguration(new RunnerAndConfigurationSettingsImpl(null, configuration, false)); + RunManagerImpl manager = (RunManagerImpl)RunManagerEx.getInstanceEx(myProject); + manager.setTemporaryConfiguration(new RunnerAndConfigurationSettingsImpl(manager, configuration, false)); return configuration; } @@ -247,7 +254,8 @@ public class ConfigurationRefactoringsTest extends BaseConfigurationTestCase { @NotNull Class producerClass, @NotNull MapDataContext dataContext) { final JUnitConfiguration configuration = super.createJUnitConfiguration(psiElement, producerClass, dataContext); - RunManagerEx.getInstanceEx(myProject).setTemporaryConfiguration(new RunnerAndConfigurationSettingsImpl(null, configuration, false)); + RunManagerImpl manager = (RunManagerImpl)RunManagerEx.getInstanceEx(myProject); + manager.setTemporaryConfiguration(new RunnerAndConfigurationSettingsImpl(manager, configuration)); return configuration; } } diff --git a/java/java-tests/testSrc/com/intellij/execution/ConfigurationsTest.java b/java/java-tests/testSrc/com/intellij/execution/ConfigurationsTest.java index 36e1b7591a44..1efc153bdb18 100644 --- a/java/java-tests/testSrc/com/intellij/execution/ConfigurationsTest.java +++ b/java/java-tests/testSrc/com/intellij/execution/ConfigurationsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -29,7 +29,6 @@ import com.intellij.execution.runners.ExecutionEnvironmentBuilder; import com.intellij.execution.testframework.SearchForTestsTask; import com.intellij.execution.testframework.TestSearchScope; import com.intellij.execution.ui.CommonJavaParametersPanel; -import com.intellij.ide.util.AppPropertiesComponentImpl; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.options.Configurable; @@ -261,12 +260,11 @@ public class ConfigurationsTest extends BaseConfigurationTestCase { JUnitConfiguration oldRc = createConfiguration(findTestA(module)); oldRc.setWorkingDirectory(module.getModuleFilePath()); - RunManagerImpl runManager = new RunManagerImpl(myProject, new AppPropertiesComponentImpl()); - Element element = new Element("configuration"); - new RunnerAndConfigurationSettingsImpl(runManager, oldRc, false).writeExternal(element); + RunManagerImpl runManager = new RunManagerImpl(myProject); + Element element = new RunnerAndConfigurationSettingsImpl(runManager, oldRc, false).writeScheme(); RunnerAndConfigurationSettingsImpl settings = new RunnerAndConfigurationSettingsImpl(runManager); - settings.readExternal(element); + settings.readExternal(element, false); JUnitConfiguration newRc = (JUnitConfiguration)settings.getConfiguration(); checkTestObject(oldRc.getPersistentData().TEST_OBJECT, newRc); diff --git a/java/java-tests/testSrc/com/intellij/execution/impl/RunConfigurableTest.java b/java/java-tests/testSrc/com/intellij/execution/impl/RunConfigurableTest.java deleted file mode 100644 index bf7050ac2884..000000000000 --- a/java/java-tests/testSrc/com/intellij/execution/impl/RunConfigurableTest.java +++ /dev/null @@ -1,737 +0,0 @@ -/* - * Copyright 2000-2017 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.execution.impl; - -import com.intellij.execution.application.ApplicationConfigurationType; -import com.intellij.execution.configurations.ConfigurationType; -import com.intellij.execution.configurations.UnknownConfigurationType; -import com.intellij.execution.junit.JUnitConfigurationType; -import com.intellij.ide.util.PropertiesComponent; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Trinity; -import com.intellij.testFramework.LightIdeaTestCase; -import com.intellij.ui.RowsDnDSupport; -import com.intellij.ui.treeStructure.Tree; -import com.intellij.util.JdomKt; -import org.jdom.Element; - -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.TreePath; -import java.util.ArrayList; -import java.util.List; - -import static com.intellij.execution.impl.RunConfigurable.NodeKind.*; -import static com.intellij.ui.RowsDnDSupport.RefinedDropSupport.Position.*; - -/** - * User: Vassiliy.Kudryashov - */ -public class RunConfigurableTest extends LightIdeaTestCase { - private static final RunConfigurable.NodeKind[] ORDER = { - CONFIGURATION_TYPE,//Application - FOLDER,//1 - CONFIGURATION, CONFIGURATION, CONFIGURATION, CONFIGURATION, CONFIGURATION, - TEMPORARY_CONFIGURATION, TEMPORARY_CONFIGURATION, - FOLDER,//2 - TEMPORARY_CONFIGURATION, - FOLDER,//3 - CONFIGURATION, - TEMPORARY_CONFIGURATION, - CONFIGURATION_TYPE,//JUnit - FOLDER,//4 - CONFIGURATION, CONFIGURATION, - FOLDER,//5 - CONFIGURATION, CONFIGURATION, - TEMPORARY_CONFIGURATION, - UNKNOWN//Defaults - }; - private MockRunConfigurable myConfigurable; - private Tree myTree; - private DefaultMutableTreeNode myRoot; - private RunConfigurable.MyTreeModel myModel; - - @Override - protected void setUp() throws Exception { - super.setUp(); - myConfigurable = new MockRunConfigurable(createRunManager(JdomKt.loadElement(FOLDERS_CONFIGURATION))); - myTree = myConfigurable.myTree; - myRoot = myConfigurable.myRoot; - myModel = myConfigurable.myTreeModel; - } - - @Override - protected void tearDown() throws Exception { - try { - if (myConfigurable != null) myConfigurable.disposeUIResources(); - myConfigurable = null; - myTree = null; - myRoot = null; - myModel = null; - } - finally { - super.tearDown(); - } - } - - public void testDND() throws Exception { - doExpand(); - int[] never = {-1, 0, 14, 22, 23, 999}; - for (int i = -1; i < 17; i++) { - for (int j : never) { - if ((j == 14 || j == 21) && i == j) { - continue; - } - assertCannot(j,i,ABOVE); - assertCannot(j,i,INTO); - assertCannot(j,i,BELOW); - } - } - assertCan(3, 3, BELOW); - assertCan(3, 3, ABOVE); - assertCannot(3, 2, BELOW); - assertCan(3, 2, ABOVE); - assertCannot(3, 1, BELOW); - assertCannot(3, 0, BELOW); - assertCan(2, 14, ABOVE); - assertCan(1, 14, ABOVE); - assertCan(1, 11, ABOVE); - assertCannot(1, 10, ABOVE); - assertCannot(1, 10, BELOW); - assertCannot(8, 6, ABOVE); - assertCan(8, 6, BELOW); - assertCannot(5, 7, BELOW); - assertCan(5, 7, ABOVE); - assertCannot(15, 11, INTO); - assertCannot(18, 21, ABOVE); - assertCan(15, 21, ABOVE); - - assertTrue(myModel.isDropInto(myTree, 2, 9)); - assertTrue(myModel.isDropInto(myTree, 2, 1)); - assertTrue(myModel.isDropInto(myTree, 12, 9)); - assertTrue(myModel.isDropInto(myTree, 12, 1)); - assertFalse(myModel.isDropInto(myTree, 999, 9)); - assertFalse(myModel.isDropInto(myTree, 999, 1)); - assertFalse(myModel.isDropInto(myTree, 2, 999)); - assertFalse(myModel.isDropInto(myTree, 2, -1)); - } - - private void doExpand() { - List toExpand = new ArrayList<>(); - RunConfigurable.collectNodesRecursively(myRoot, toExpand, FOLDER); - assertEquals(5, toExpand.size()); - List toExpand2 = new ArrayList<>(); - RunConfigurable.collectNodesRecursively(myRoot, toExpand2, CONFIGURATION_TYPE); - toExpand.addAll(toExpand2); - for (DefaultMutableTreeNode node : toExpand) { - myTree.expandPath(new TreePath(node.getPath())); - } - for (int i = 0; i < ORDER.length; i++) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode)myTree.getPathForRow(i).getLastPathComponent(); - assertEquals("Row #" + i, RunConfigurable.getKind(node), ORDER[i]); - } - } - - private void assertCan(int oldIndex, int newIndex, RowsDnDSupport.RefinedDropSupport.Position position) { - assertDrop(oldIndex, newIndex, position, true); - } - - private void assertCannot(int oldIndex, int newIndex, RowsDnDSupport.RefinedDropSupport.Position position) { - assertDrop(oldIndex, newIndex, position, false); - } - - private void assertDrop(int oldIndex, int newIndex, RowsDnDSupport.RefinedDropSupport.Position position, boolean canDrop) { - StringBuilder message = new StringBuilder(); - message.append("(").append(oldIndex).append(")").append(myTree.getPathForRow(oldIndex)).append("->"); - message.append("(").append(newIndex).append(")").append(myTree.getPathForRow(newIndex)).append(position); - if (canDrop) { - assertTrue(message.toString(), myModel.canDrop(oldIndex, newIndex, position)); - } - else { - assertFalse(message.toString(), myModel.canDrop(oldIndex, newIndex, position)); - } - } - - public void testMoveUpDown() { - doExpand(); - checkPositionToMove(0, 1, null); - checkPositionToMove(2, 1, Trinity.create(2, 3, BELOW)); - checkPositionToMove(2, -1, null); - checkPositionToMove(14, 1, null); - checkPositionToMove(14, -1, null); - checkPositionToMove(15, -1, null); - checkPositionToMove(16, -1, null); - checkPositionToMove(3, -1, Trinity.create(3, 2, ABOVE)); - checkPositionToMove(6, 1, Trinity.create(6, 9, BELOW)); - checkPositionToMove(7, 1, Trinity.create(7, 8, BELOW)); - checkPositionToMove(10, -1, Trinity.create(10, 8, BELOW)); - checkPositionToMove(8, 1, Trinity.create(8, 9, BELOW)); - checkPositionToMove(21, -1, Trinity.create(21, 20, BELOW)); - checkPositionToMove(21, 1, null); - checkPositionToMove(20, 1, Trinity.create(20, 21, ABOVE)); - checkPositionToMove(20, -1, Trinity.create(20, 19, ABOVE)); - checkPositionToMove(19, 1, Trinity.create(19, 20, BELOW)); - checkPositionToMove(19, -1, Trinity.create(19, 17, BELOW)); - checkPositionToMove(17, -1, Trinity.create(17, 16, ABOVE)); - checkPositionToMove(17, 1, Trinity.create(17, 18, BELOW)); - } - - private void checkPositionToMove(int selectedRow, - int direction, - Trinity expected) { - myTree.setSelectionRow(selectedRow); - assertEquals(expected, myConfigurable.getAvailableDropPosition(direction)); - } - - private static RunManagerImpl createRunManager(Element element) { - Project project = getProject(); - RunManagerImpl runManager = new RunManagerImpl(project, PropertiesComponent.getInstance(project)); - runManager.initializeConfigurationTypes(new ConfigurationType[]{ApplicationConfigurationType.getInstance(), - JUnitConfigurationType.getInstance(), UnknownConfigurationType.INSTANCE}); - runManager.loadState(element); - return runManager; - } - - private static class MockRunConfigurable extends RunConfigurable { - private final RunManagerImpl myTestManager; - - private MockRunConfigurable(RunManagerImpl runManager) { - super(getProject()); - myTestManager = runManager; - createComponent(); - } - - @Override - RunManagerImpl getRunManager() { - return myTestManager; - } - } - - /* -00 Application -01 1 -02 CodeGenerator -03 Renamer -04 UI -05 AuTest -06 Simples -07 OutAndErr (tmp) -08 C148C_TersePrincess (tmp) -09 2 -10 Periods (tmp) -11 3 -12 C148E_Porcelain -13 ErrAndOut (tmp) -14 JUnit -15 4 -16 All in titled -17 All in titled2 -18 5 -19 All in titled3 -20 All in titled4 -21 All in titled5 -16 Defaults - ... - */ - private static final String FOLDERS_CONFIGURATION = " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " localhost\n" + - " 5050\n" + - " \n" + - " \n"; -} diff --git a/java/java-tests/testSrc/com/intellij/execution/impl/RunConfigurableTest.kt b/java/java-tests/testSrc/com/intellij/execution/impl/RunConfigurableTest.kt new file mode 100644 index 000000000000..a10c98304b95 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/execution/impl/RunConfigurableTest.kt @@ -0,0 +1,194 @@ +/* + * Copyright 2000-2017 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.execution.impl + +import com.intellij.execution.application.ApplicationConfigurationType +import com.intellij.execution.impl.RunConfigurable.NodeKind.* +import com.intellij.execution.junit.JUnitConfigurationType +import com.intellij.openapi.util.Trinity +import com.intellij.testFramework.LightIdeaTestCase +import com.intellij.testFramework.LightPlatformTestCase +import com.intellij.testFramework.assertions.Assertions.assertThat +import com.intellij.ui.RowsDnDSupport +import com.intellij.ui.RowsDnDSupport.RefinedDropSupport.Position.* +import com.intellij.ui.treeStructure.Tree +import com.intellij.util.loadElement +import org.jdom.Element +import java.util.* +import javax.swing.tree.DefaultMutableTreeNode +import javax.swing.tree.TreePath +import kotlin.properties.Delegates + +private val ORDER = arrayOf(CONFIGURATION_TYPE, //Application + FOLDER, //1 + CONFIGURATION, CONFIGURATION, CONFIGURATION, CONFIGURATION, CONFIGURATION, TEMPORARY_CONFIGURATION, TEMPORARY_CONFIGURATION, FOLDER, //2 + TEMPORARY_CONFIGURATION, FOLDER, //3 + CONFIGURATION, TEMPORARY_CONFIGURATION, CONFIGURATION_TYPE, //JUnit + FOLDER, //4 + CONFIGURATION, CONFIGURATION, FOLDER, //5 + CONFIGURATION, CONFIGURATION, TEMPORARY_CONFIGURATION, UNKNOWN//Defaults +) + +private fun createRunManager(element: Element): RunManagerImpl { + val runManager = RunManagerImpl(LightPlatformTestCase.getProject()) + runManager.initializeConfigurationTypes(arrayOf(ApplicationConfigurationType.getInstance(), JUnitConfigurationType.getInstance())) + runManager.loadState(element) + return runManager +} + +class RunConfigurableTest : LightIdeaTestCase() { + private var configurable: MockRunConfigurable? = null + private var tree: Tree by Delegates.notNull() + private var root: DefaultMutableTreeNode? = null + private var model: RunConfigurable.MyTreeModel by Delegates.notNull() + + override fun setUp() { + super.setUp() + + configurable = MockRunConfigurable(createRunManager(loadElement(RunConfigurableTest::class.java.getResourceAsStream("folders.xml")))) + tree = configurable!!.myTree + root = configurable!!.myRoot + model = configurable!!.myTreeModel + } + + override fun tearDown() { + try { + if (configurable != null) { + configurable!!.disposeUIResources() + } + configurable = null + root = null + } + finally { + super.tearDown() + } + } + + fun testDND() { + doExpand() + val never = intArrayOf(-1, 0, 14, 22, 23, 999) + for (i in -1..16) { + for (j in never) { + if ((j == 14 || j == 21) && i == j) { + continue + } + assertCannot(j, i, ABOVE) + assertCannot(j, i, INTO) + assertCannot(j, i, BELOW) + } + } + assertCan(3, 3, BELOW) + assertCan(3, 3, ABOVE) + assertCannot(3, 2, BELOW) + assertCan(3, 2, ABOVE) + assertCannot(3, 1, BELOW) + assertCannot(3, 0, BELOW) + assertCan(2, 14, ABOVE) + assertCan(1, 14, ABOVE) + assertCan(1, 11, ABOVE) + assertCannot(1, 10, ABOVE) + assertCannot(1, 10, BELOW) + assertCannot(8, 6, ABOVE) + assertCan(8, 6, BELOW) + assertCannot(5, 7, BELOW) + assertCan(5, 7, ABOVE) + assertCannot(15, 11, INTO) + assertCannot(18, 21, ABOVE) + assertCan(15, 21, ABOVE) + + assertThat(model.isDropInto(tree, 2, 9)).isTrue() + assertThat(model.isDropInto(tree, 2, 1)).isTrue() + assertThat(model.isDropInto(tree, 12, 9)).isTrue() + assertThat(model.isDropInto(tree, 12, 1)).isTrue() + assertThat(model.isDropInto(tree, 999, 9)).isFalse() + assertThat(model.isDropInto(tree, 999, 1)).isFalse() + assertThat(model.isDropInto(tree, 2, 999)).isFalse() + assertThat(model.isDropInto(tree, 2, -1)).isFalse() + } + + private fun doExpand() { + val toExpand = ArrayList() + RunConfigurable.collectNodesRecursively(root, toExpand, FOLDER) + assertThat(toExpand).hasSize(5) + val toExpand2 = ArrayList() + RunConfigurable.collectNodesRecursively(root, toExpand2, CONFIGURATION_TYPE) + toExpand.addAll(toExpand2) + for (node in toExpand) { + tree.expandPath(TreePath(node.path)) + } + + assertThat(ORDER.mapIndexed { index, nodeKind -> RunConfigurable.getKind(tree.getPathForRow(index).lastPathComponent as DefaultMutableTreeNode) }).containsExactly(*ORDER) + } + + private fun assertCan(oldIndex: Int, newIndex: Int, position: RowsDnDSupport.RefinedDropSupport.Position) { + assertDrop(oldIndex, newIndex, position, true) + } + + private fun assertCannot(oldIndex: Int, newIndex: Int, position: RowsDnDSupport.RefinedDropSupport.Position) { + assertDrop(oldIndex, newIndex, position, false) + } + + private fun assertDrop(oldIndex: Int, newIndex: Int, position: RowsDnDSupport.RefinedDropSupport.Position, canDrop: Boolean) { + val message = StringBuilder() + message.append("(").append(oldIndex).append(")").append(tree.getPathForRow(oldIndex)).append("->") + message.append("(").append(newIndex).append(")").append(tree.getPathForRow(newIndex)).append(position) + if (canDrop) { + // message.toString() + assertThat(model.canDrop(oldIndex, newIndex, position)).isTrue() + } + else { + // message.toString() + assertThat(model.canDrop(oldIndex, newIndex, position)).isFalse() + } + } + + fun testMoveUpDown() { + doExpand() + checkPositionToMove(0, 1, null) + checkPositionToMove(2, 1, Trinity.create(2, 3, BELOW)) + checkPositionToMove(2, -1, null) + checkPositionToMove(14, 1, null) + checkPositionToMove(14, -1, null) + checkPositionToMove(15, -1, null) + checkPositionToMove(16, -1, null) + checkPositionToMove(3, -1, Trinity.create(3, 2, ABOVE)) + checkPositionToMove(6, 1, Trinity.create(6, 9, BELOW)) + checkPositionToMove(7, 1, Trinity.create(7, 8, BELOW)) + checkPositionToMove(10, -1, Trinity.create(10, 8, BELOW)) + checkPositionToMove(8, 1, Trinity.create(8, 9, BELOW)) + checkPositionToMove(21, -1, Trinity.create(21, 20, BELOW)) + checkPositionToMove(21, 1, null) + checkPositionToMove(20, 1, Trinity.create(20, 21, ABOVE)) + checkPositionToMove(20, -1, Trinity.create(20, 19, ABOVE)) + checkPositionToMove(19, 1, Trinity.create(19, 20, BELOW)) + checkPositionToMove(19, -1, Trinity.create(19, 17, BELOW)) + checkPositionToMove(17, -1, Trinity.create(17, 16, ABOVE)) + checkPositionToMove(17, 1, Trinity.create(17, 18, BELOW)) + } + + private fun checkPositionToMove(selectedRow: Int, direction: Int, expected: Trinity?) { + tree.setSelectionRow(selectedRow) + assertThat(configurable!!.getAvailableDropPosition(direction)).isEqualTo(expected) + } +} + +private class MockRunConfigurable(private val testManager: RunManagerImpl) : RunConfigurable(LightPlatformTestCase.getProject()) { + init { + createComponent() + } + + internal override fun getRunManager() = testManager +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/execution/impl/folders.xml b/java/java-tests/testSrc/com/intellij/execution/impl/folders.xml new file mode 100644 index 000000000000..a32681bd5e72 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/execution/impl/folders.xml @@ -0,0 +1,489 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + localhost + 5050 + + \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/index/ConcurrentIndexTest.groovy b/java/java-tests/testSrc/com/intellij/index/ConcurrentIndexTest.groovy index 58ae726f6824..befbc0176107 100644 --- a/java/java-tests/testSrc/com/intellij/index/ConcurrentIndexTest.groovy +++ b/java/java-tests/testSrc/com/intellij/index/ConcurrentIndexTest.groovy @@ -48,7 +48,7 @@ class ConcurrentIndexTest extends JavaCodeInsightFixtureTestCase { void "test concurrent switching with checkCanceled"() { def N = Math.max(2, (int)(Runtime.runtime.availableProcessors())) - def halfN = N / 2 + int halfN = N / 2 for (iteration in 1..200) { def name = "Foo" + iteration // if (iteration % 10 == 0) println "Finding $name" @@ -96,7 +96,7 @@ class ConcurrentIndexTest extends JavaCodeInsightFixtureTestCase { void "test cancellable and non-cancellable progress"() { def N = Math.max(2, (int)(Runtime.runtime.availableProcessors())) - def halfN = N / 2 + int halfN = N / 2 PsiFileImpl file = (PsiFileImpl) myFixture.addFileToProject("Foo.java", "class Foo {" + ("public void foo() {}\n") * 1000 + "}") assert myFixture.findClass("Foo").node @@ -139,7 +139,7 @@ class ConcurrentIndexTest extends JavaCodeInsightFixtureTestCase { void "test forceUpdateAffectsReadOfDataForUnsavedDocuments"() { def N = Math.max(2, (int)(Runtime.runtime.availableProcessors())) - def halfN = N / 2 + int halfN = N / 2 PsiFileImpl file = (PsiFileImpl) myFixture.addFileToProject("Foo.java", "class Foo {" + ("public void foo() {}\n") * 1000 + "}") assert myFixture.findClass("Foo").node @@ -183,7 +183,7 @@ class ConcurrentIndexTest extends JavaCodeInsightFixtureTestCase { void "test concurrent light AST access during uncommitted document indexing"() { def clazz = myFixture.addClass('class Bar { void foo(Object o) {}}') - def text = " foo(null);"; + def text = " foo(null);" for (i in 0..20) { text = "new Runnable() { void run() {\n " + text + "\n}}.run();" } diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy index 29a31581c9e5..5cf526a20a09 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy @@ -506,13 +506,14 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { } void "test report using index from other index"() throws IOException { - def vfile = myFixture.addClass("class Foo { void bar() {} }").getContainingFile().getVirtualFile() + def className = "Foo" + def vfile = myFixture.addClass("class $className { void bar() {} }").getContainingFile().getVirtualFile() def scope = GlobalSearchScope.allScope(project) def foundClass = [false] def foundMethod = [false] try { - StubIndex.instance.processElements(JavaStubIndexKeys.CLASS_SHORT_NAMES, "Foo", project, scope, + StubIndex.instance.processElements(JavaStubIndexKeys.CLASS_SHORT_NAMES, className, project, scope, PsiClass.class, new Processor() { @Override @@ -537,6 +538,35 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { assertTrue(foundClass[0]) assertTrue(!foundMethod[0]) + def foundClassProcessAll = [false] + def foundClassStub = [false] + + try { + StubIndex.instance.processAllKeys(JavaStubIndexKeys.CLASS_SHORT_NAMES, project, + new Processor() { + @Override + boolean process(String aClass) { + if (!className.equals(aClass)) return true; + foundClassProcessAll[0] = true + StubIndex.instance.processElements(JavaStubIndexKeys.CLASS_SHORT_NAMES, aClass, project, scope, + PsiClass.class, + new Processor() { + @Override + boolean process(PsiClass clazz) { + foundClassStub[0] = true + return true + } + }) + return true + } + }) + } catch (e) { + if (!(e instanceof RuntimeException)) throw e + } + + assertTrue(foundClassProcessAll[0]) + assertTrue(!foundClassStub[0]) + def foundId = [false] def foundStub = [false] @@ -668,6 +698,12 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { assert JavaFileElementType.isInSourceContent(myFixture.tempDirFixture.getFile('another/doo/A.java')) } + void "test requesting nonexisted index fails as expected"() { + ID myId = ID.create("my.id") + FileBasedIndex.instance.getContainingFiles(myId, "null", GlobalSearchScope.allScope(project)) + FileBasedIndex.instance.processAllKeys(myId, Processor.TRUE, project) + } + void "test read-only index access"() { StringIndex index = createIndex(getTestName(false), new EnumeratorStringDescriptor(), true) diff --git a/java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy b/java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy index 5f0a8d27269c..e39e720228f7 100644 --- a/java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy +++ b/java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,15 +33,18 @@ import com.intellij.psi.stubs.StubTree import com.intellij.psi.util.PsiTreeUtil import com.intellij.reference.SoftReference import com.intellij.testFramework.LeakHunter +import com.intellij.testFramework.SkipSlowTestLocally import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import com.intellij.util.ref.GCUtil import java.util.concurrent.Callable import java.util.concurrent.CountDownLatch import java.util.concurrent.Future + /** * @author peter */ +@SkipSlowTestLocally class StubAstSwitchTest extends LightCodeInsightFixtureTestCase { void "test modifying file with stubs via VFS"() { @@ -108,7 +111,7 @@ class StubAstSwitchTest extends LightCodeInsightFixtureTestCase { PsiFile file = myFixture.addFileToProject("A.java", "class A {}") def oldClass = JavaPsiFacade.getInstance(project).findClass("A", GlobalSearchScope.allScope(project)) def pointer = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(oldClass) - + def document = FileDocumentManager.instance.getDocument(file.virtualFile) assert document assert file == PsiDocumentManager.getInstance(project).getCachedPsiFile(document) diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java index fc7e9141459f..ee1b6fa7c8ee 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java @@ -192,7 +192,7 @@ public class JavaFormatterTest extends AbstractJavaFormatterTest { public void testWrapAssertion() throws Exception { doTest(); } - + public void testIfElse() throws Exception { final CommonCodeStyleSettings settings = getSettings(); settings.IF_BRACE_FORCE = CommonCodeStyleSettings.DO_NOT_FORCE; @@ -2303,7 +2303,8 @@ public void testSCR260() throws Exception { getSettings().KEEP_SIMPLE_METHODS_IN_ONE_LINE = false; getSettings().KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = true; getSettings().METHOD_BRACE_STYLE = CommonCodeStyleSettings.END_OF_LINE; - + getSettings().CASE_STATEMENT_ON_NEW_LINE = false; + doTextTest("class Foo{\n" + "void foo() {\n" + "if(a) {return;}\n" + @@ -2317,11 +2318,7 @@ public void testSCR260() throws Exception { " void foo() {\n" + " if (a) {return;}\n" + " for (a = 0; a < 10; a++) {return;}\n" + - " switch (a)\n" + - " {\n" + - " case 1:\n" + - " return;\n" + - " }\n" + + " switch (a) {case 1: return;}\n" + " do {return;} while (a);\n" + " while (a) {return;}\n" + " try {return;} catch (Ex e) {return;} finally {return;}\n" + @@ -3329,4 +3326,43 @@ public void testSCR260() throws Exception { ); } + public void testKeepSimpleSwitchInOneLine() { + getSettings().CASE_STATEMENT_ON_NEW_LINE = false; + doMethodTest( + "switch (b) {\n" + + "case 1: case 2: break;\n" + + "}", + "switch (b) {\n" + + " case 1: case 2: break;\n" + + "}"); + } + + public void testExpandSwitch() { + getSettings().CASE_STATEMENT_ON_NEW_LINE = false; + doMethodTest( + "switch (b) {\n" + + "case 1: { println(1); } case 2: break;\n" + + "}", + "switch (b) {\n" + + " case 1: {\n" + + " println(1);\n" + + " }\n" + + " case 2: break;\n" + + "}"); + } + + public void testKeepBreakOnSameLine() { + getSettings().CASE_STATEMENT_ON_NEW_LINE = false; + doMethodTest( + "switch (b) {\n" + + "case 1: case 2:\n" + + "\n\n\n\n\n\n" + + "break;\n" + + "}", + "switch (b) {\n" + + " case 1: case 2:\n\n\n" + + " break;\n" + + "}"); + } + } diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/PsiEventsTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/PsiEventsTest.java index 9681d9e2bc82..e7d41970d988 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/PsiEventsTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/PsiEventsTest.java @@ -16,6 +16,7 @@ package com.intellij.psi.impl.file.impl; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; @@ -814,4 +815,18 @@ public class PsiEventsTest extends PsiTestCase { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); assertEquals(" ", getPsiManager().findFile(vFile).getText()); } + + public void testCopyFile() throws Exception { + VirtualFile original = createFile(myModule, mySrcDir1, "a.xml", "").getVirtualFile(); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + PsiDirectory psiDir2 = PsiManager.getInstance(myProject).findDirectory(mySrcDir2); + assertNotNull(psiDir2); + WriteAction.run(() -> original.copy(this, mySrcDir2, "b.xml")); + + assertEquals("beforeChildAddition\n" + + "childAdded\n", listener.getEventsString()); + } } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java index 4150827856dc..a528d18f38c7 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java @@ -60,7 +60,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testSimpleGeneration() throws Exception { doTest("int i = 0; int j = 0;", "Test test = new Test().invoke();int i = test.getI();int j = test.getJ();", - "public static class Test {\n" + + "static class Test {\n" + " private int i;\n" + " private int j;\n" + "\n" + @@ -83,7 +83,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testInvokeReturnType() throws Exception { doTest("x = 6; y = 6;", "Test test = new Test().invoke();x = test.getX();y = test.getY();", - "public static class Test {\n" + + "static class Test {\n" + " private int x;\n" + " private int y;\n" + "\n" + @@ -106,8 +106,8 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testAnonymousClassParams() throws Exception { doTest("new I() {public void foo(int i) {i++;}};", "I result = Test.invoke();", - "public static class Test {\n" + - " public static I invoke() {\n" + + "static class Test {\n" + + " static I invoke() {\n" + " return new I() {\n" + " public void foo(int i) {\n" + " i++;\n" + @@ -120,7 +120,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testInnerClass() throws Exception { doTest(" new I(2).foo()", "new Test().invoke();", - "public class Test {\n" + + "class Test {\n" + " public void invoke() {\n" + " new Sample.I(2).foo();\n" + " }\n" + @@ -130,7 +130,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testResultExpr() throws Exception { doTest(" foo()", "int result = new Test().invoke();", - "public class Test {\n" + + "class Test {\n" + " public int invoke() {\n" + " return foo();\n" + " }\n" + @@ -140,7 +140,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testResultStatements() throws Exception { doTest("int i = 0;\nfoo()", "Test test = new Test().invoke();int i = test.getI();int result = test.getResult();", - "public class Test {\n" + + "class Test {\n" + " private int i;\n" + " private int result;\n" + "\n" + @@ -164,7 +164,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testOffsetsAtCallSite() throws Exception { doTest("map.entrySet().stream().filter((a) -> (a.getKey()>0));", "Stream> result = new Test(map).invoke();", - "public static class Test {\n" + + "static class Test {\n" + " private Map map;\n" + "\n" + " public Test(Map map) {\n" + @@ -178,8 +178,8 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { } public void testHangingFunctionalExpressions() throws Exception { - doTest("() -> {}", "Test.invoke();", "public static class Test {\n" + - " public static void invoke() {\n" + + doTest("() -> {}", "Test.invoke();", "static class Test {\n" + + " static void invoke() {\n" + " () -> {\n" + " };\n" + " }\n" + @@ -189,8 +189,8 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testArrayInitializer() throws Exception { doTest("{new Runnable() {public void run(){} } }", "Runnable[] result = Test.invoke();", - "public static class Test {\n" + - " public static Runnable[] invoke() {\n" + + "static class Test {\n" + + " static Runnable[] invoke() {\n" + " return new Runnable[]{new Runnable() {\n" + " public void run() {\n" + " }\n" + @@ -202,8 +202,8 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testNewArrayInitializer() throws Exception { doTest("new Runnable[] {new Runnable() {public void run(){} } }", "Runnable[] result = Test.invoke();", - "public static class Test {\n" + - " public static Runnable[] invoke() {\n" + + "static class Test {\n" + + " static Runnable[] invoke() {\n" + " return new Runnable[]{new Runnable() {\n" + " public void run() {\n" + " }\n" + @@ -227,7 +227,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { " foo();\n" + " });", "new Test(list).invoke();", - "public class Test {\n" + + "class Test {\n" + " private List list;\n" + "\n" + " public Test(List list) {\n" + @@ -256,7 +256,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testOnClosingBrace() throws Exception { doTest(" foo()", "int result = new Test().invoke();", - "public class Test {\n" + + "class Test {\n" + " public int invoke() {\n" + " return foo();\n" + " }\n" + @@ -266,7 +266,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testOnClosingBraceLocalClass() throws Exception { doTest(" foo()", "int result = new Test().invoke();", - "public class Test {\n" + + "class Test {\n" + " public int invoke() {\n" + " return foo();\n" + " }\n" + @@ -276,7 +276,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testOnFieldInitialization() throws Exception { doTest(" foo()", "int result = new Test().invoke();", - "public class Test {\n" + + "class Test {\n" + " public int invoke() {\n" + " return foo();\n" + " }\n" + @@ -286,8 +286,8 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testOnEmptyMethod() throws Exception { doTest(" foo()", "int result = Test.invoke();", - "public static class Test {\n" + - " public static int invoke() {\n" + + "static class Test {\n" + + " static int invoke() {\n" + " return foo();\n" + " }\n" + " }"); @@ -296,7 +296,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testOnSuperConstructorCall() throws Exception { doTest(" foo()", "int result = new Test().invoke();", - "public class Test {\n" + + "class Test {\n" + " public int invoke() {\n" + " return foo();\n" + " }\n" + @@ -306,7 +306,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { public void testOnPrivateField() throws Exception { doTest(" foo()", "int result = new Test().invoke();", - "public class Test {\n" + + "class Test {\n" + " public int invoke() {\n" + " return foo();\n" + " }\n" + diff --git a/java/java-tests/testSrc/com/intellij/refactoring/MovePackageTest.java b/java/java-tests/testSrc/com/intellij/refactoring/MovePackageTest.java index d60e7f0f90f4..caf741958725 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/MovePackageTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/MovePackageTest.java @@ -15,14 +15,16 @@ */ package com.intellij.refactoring; +import com.intellij.JavaTestUtil; import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.project.Project; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPackage; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesProcessor; import com.intellij.refactoring.move.moveClassesOrPackages.SingleSourceRootMoveDestination; -import com.intellij.JavaTestUtil; import org.jetbrains.annotations.NotNull; public class MovePackageTest extends MultiFileTestCase { @@ -49,6 +51,12 @@ public class MovePackageTest extends MultiFileTestCase { doTest(new String[]{"a"}, "a.b"); } + public void testPackageAndReferencedClass() throws Exception { + Project project = myPsiManager.getProject(); + JavaPsiFacade facade = JavaPsiFacade.getInstance(project); + doTest((rootDir, rootAfter) -> performAction(new PsiElement[]{facade.findPackage("a"), facade.findClass("B", GlobalSearchScope.allScope(project))}, "b")); + } + @NotNull @Override protected String getTestRoot() { @@ -67,12 +75,16 @@ public class MovePackageTest extends MultiFileTestCase { assertNotNull("Package " + packageName + " not found", packages[i]); } + performAction(packages, newPackageName); + } + + private void performAction(PsiElement[] packagesAndClasses, String newPackageName) { PsiPackage newParentPackage = JavaPsiFacade.getInstance(myPsiManager.getProject()).findPackage(newPackageName); assertNotNull(newParentPackage); final PsiDirectory[] dirs = newParentPackage.getDirectories(); assertEquals(dirs.length, 1); - new MoveClassesOrPackagesProcessor(myProject, packages, + new MoveClassesOrPackagesProcessor(myProject, packagesAndClasses, new SingleSourceRootMoveDestination(PackageWrapper.create(newParentPackage), dirs[0]), true, false, null).run(); FileDocumentManager.getInstance().saveAllDocuments(); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstance8MethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstance8MethodTest.java index 745be3a6476f..f6ee7dd856c2 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstance8MethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstance8MethodTest.java @@ -15,7 +15,9 @@ */ package com.intellij.refactoring.convertToInstanceMethod; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; +import com.intellij.refactoring.BaseRefactoringProcessor; public class ConvertToInstance8MethodTest extends ConvertToInstanceMethodTest { @Override @@ -23,6 +25,31 @@ public class ConvertToInstance8MethodTest extends ConvertToInstanceMethodTest { return "/refactoring/convertToInstance8Method/"; } + public void testThisInsteadOfNoQualifier() throws Exception { + doTest(0); + } + + public void testMethodReferenceAcceptableBySecondSearch() throws Exception { + doTest(0); + } + + public void testConvertToInstanceMethodOfTheSameClass() throws Exception { + doTest(-1); + } + + public void testConvertToInstanceMethodOfTheSameClassWithTypeParams() throws Exception { + try { + doTest(-1); + } + catch (BaseRefactoringProcessor.ConflictsInTestsException e) { + assertEquals(StringUtil.trimEnd(StringUtil.repeat("Impossible to infer class type arguments. When proceed, raw Bar would be created\n", 3), "\n"), e.getMessage()); + } + } + + public void testMethodReferenceToLambda() throws Exception { + BaseRefactoringProcessor.ConflictsInTestsException.withIgnoredConflicts(() -> doTest(1)); + } + @Override protected LanguageLevel getLanguageLevel() { return LanguageLevel.JDK_1_8; diff --git a/java/java-tests/testSrc/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodTest.java index 300ddadee60c..ab21da215b16 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodTest.java @@ -51,7 +51,7 @@ public class ConvertToInstanceMethodTest extends LightRefactoringTestCase { } } - private void doTest(final int targetParameter) throws Exception { + protected void doTest(final int targetParameter) throws Exception { doTest(targetParameter, VisibilityUtil.ESCALATE_VISIBILITY); } @@ -62,7 +62,7 @@ public class ConvertToInstanceMethodTest extends LightRefactoringTestCase { assertTrue(" is not on method name", targetElement instanceof PsiMethod); PsiMethod method = (PsiMethod) targetElement; new ConvertToInstanceMethodProcessor(getProject(), - method, method.getParameterList().getParameters()[targetParameter], + method, targetParameter < 0 ? null : method.getParameterList().getParameters()[targetParameter], visibility).run(); checkResultByFile(filePath + ".after"); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/moveMethod/MoveInstanceMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/moveMethod/MoveInstanceMethodTest.java index 4dc98f3c2a61..2266b70dfb68 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/moveMethod/MoveInstanceMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/moveMethod/MoveInstanceMethodTest.java @@ -90,19 +90,17 @@ public class MoveInstanceMethodTest extends LightRefactoringTestCase { } public void testMethodReference() throws Exception { - try { - doTest(true, 0); - fail("Conflict was not detected"); - } - catch (BaseRefactoringProcessor.ConflictsInTestsException e) { - assertEquals("Method reference would be broken after move", e.getMessage()); - } + BaseRefactoringProcessor.ConflictsInTestsException.withIgnoredConflicts(() -> doTest(true, 0)); } public void testThisMethodReferenceWithTargetField() throws Exception { doTest(false, 0); } + public void testMethodReferenceToExpandToLambda() throws Exception { + BaseRefactoringProcessor.ConflictsInTestsException.withIgnoredConflicts(() -> doTest(true, 1)); + } + public void testForeignMethodReferenceWithTargetField() throws Exception { doTest(false, 0); } diff --git a/java/java-tests/testSrc/com/intellij/testFramework/fixtures/LightJava9ModulesCodeInsightFixtureTestCase.kt b/java/java-tests/testSrc/com/intellij/testFramework/fixtures/LightJava9ModulesCodeInsightFixtureTestCase.kt index d69d576aa500..562f156ff68d 100644 --- a/java/java-tests/testSrc/com/intellij/testFramework/fixtures/LightJava9ModulesCodeInsightFixtureTestCase.kt +++ b/java/java-tests/testSrc/com/intellij/testFramework/fixtures/LightJava9ModulesCodeInsightFixtureTestCase.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -30,5 +30,8 @@ abstract class LightJava9ModulesCodeInsightFixtureTestCase : LightCodeInsightFix } protected fun addFile(path: String, text: String, module: ModuleDescriptor = MAIN): VirtualFile = - VfsTestUtil.createFile(module.root(), path, text) + VfsTestUtil.createFile(module.root(), path, text) + + protected fun addTestFile(path: String, text: String): VirtualFile = + VfsTestUtil.createFile(MAIN.testRoot()!!, path, text) } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/testFramework/fixtures/MultiModuleJava9ProjectDescriptor.kt b/java/java-tests/testSrc/com/intellij/testFramework/fixtures/MultiModuleJava9ProjectDescriptor.kt index d19515e2352c..cd0abf9e0386 100644 --- a/java/java-tests/testSrc/com/intellij/testFramework/fixtures/MultiModuleJava9ProjectDescriptor.kt +++ b/java/java-tests/testSrc/com/intellij/testFramework/fixtures/MultiModuleJava9ProjectDescriptor.kt @@ -28,6 +28,7 @@ import com.intellij.openapi.vfs.ex.temp.TempFileSystem import com.intellij.pom.java.LanguageLevel import com.intellij.testFramework.IdeaTestUtil import com.intellij.testFramework.LightPlatformTestCase +import org.jetbrains.jps.model.java.JavaSourceRootType /** * Dependencies: 'main' -> 'm2', 'main' -> 'm4', 'main' -> 'm5', 'main' -> 'm6' => 'm7' @@ -43,7 +44,10 @@ object MultiModuleJava9ProjectDescriptor : DefaultLightProjectDescriptor() { M7("${TEST_MODULE_NAME}_m7", "src_m7"); fun root(): VirtualFile = - if (this == MAIN) LightPlatformTestCase.getSourceRoot() else TempFileSystem.getInstance().findFileByPath("/$rootName")!! + if (this == MAIN) LightPlatformTestCase.getSourceRoot() else TempFileSystem.getInstance().findFileByPath("/$rootName")!! + + fun testRoot(): VirtualFile? = + if (this == MAIN) TempFileSystem.getInstance().findFileByPath("/test_src")!! else null } override fun getSdk(): Sdk = IdeaTestUtil.getMockJdk9() @@ -89,12 +93,18 @@ object MultiModuleJava9ProjectDescriptor : DefaultLightProjectDescriptor() { override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) { model.getModuleExtension(LanguageLevelModuleExtension::class.java).languageLevel = LanguageLevel.JDK_1_9 + if (module.name == TEST_MODULE_NAME) { + val testRoot = createSourceRoot(module, "test_src") + registerSourceRoot(module.project, testRoot) + model.addContentEntry(testRoot).addSourceFolder(testRoot, JavaSourceRootType.TEST_SOURCE) + } } fun cleanupSourceRoots() = runWriteAction { ModuleDescriptor.values().asSequence() - .filter { it != ModuleDescriptor.MAIN } - .flatMap { it.root().children.asSequence() } - .forEach { it.delete(this) } + .filter { it != ModuleDescriptor.MAIN } + .flatMap { it.root().children.asSequence() } + .plus(ModuleDescriptor.MAIN.testRoot()!!.children.asSequence()) + .forEach { it.delete(this) } } } \ No newline at end of file diff --git a/java/openapi/src/com/intellij/codeInsight/CodeInsightServicesUtil.java b/java/openapi/src/com/intellij/codeInsight/CodeInsightServicesUtil.java index c9f28724dc17..a93a15836113 100644 --- a/java/openapi/src/com/intellij/codeInsight/CodeInsightServicesUtil.java +++ b/java/openapi/src/com/intellij/codeInsight/CodeInsightServicesUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -78,15 +78,18 @@ public class CodeInsightServicesUtil { } } else if (booleanExpression instanceof PsiLiteralExpression) { - return booleanExpression.getText().equals("true") ? - factory.createExpressionFromText("false", null) : - factory.createExpressionFromText("true", null); + Object value = ((PsiLiteralExpression)booleanExpression).getValue(); + if (value instanceof Boolean) { + return factory.createExpressionFromText(String.valueOf(!((Boolean)value)), booleanExpression); + } } if (booleanExpression instanceof PsiParenthesizedExpression) { PsiExpression operand = ((PsiParenthesizedExpression)booleanExpression).getExpression(); - operand.replace(invertCondition(operand)); - return booleanExpression; + if (operand != null) { + operand.replace(invertCondition(operand)); + return booleanExpression; + } } PsiPrefixExpression result = (PsiPrefixExpression)factory.createExpressionFromText("!(a)", null); diff --git a/java/openapi/src/com/intellij/ide/util/projectWizard/JavaModuleBuilder.java b/java/openapi/src/com/intellij/ide/util/projectWizard/JavaModuleBuilder.java index 26a3a7cfc417..5a3be03ad43e 100644 --- a/java/openapi/src/com/intellij/ide/util/projectWizard/JavaModuleBuilder.java +++ b/java/openapi/src/com/intellij/ide/util/projectWizard/JavaModuleBuilder.java @@ -157,6 +157,7 @@ public class JavaModuleBuilder extends ModuleBuilder implements SourcePathsBuild public List commit(@NotNull Project project, ModifiableModuleModel model, ModulesProvider modulesProvider) { LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(ProjectManager.getInstance().getDefaultProject()); Boolean aDefault = extension.getDefault(); + LOG.debug("commit: aDefault=" + aDefault); LanguageLevelProjectExtension instance = LanguageLevelProjectExtension.getInstance(project); if (aDefault != null && !aDefault) { instance.setLanguageLevel(extension.getLanguageLevel()); diff --git a/java/openapi/src/com/intellij/jarRepository/RemoteRepositoryDescription.java b/java/openapi/src/com/intellij/jarRepository/RemoteRepositoryDescription.java index 9988139d8c39..344ca732190c 100644 --- a/java/openapi/src/com/intellij/jarRepository/RemoteRepositoryDescription.java +++ b/java/openapi/src/com/intellij/jarRepository/RemoteRepositoryDescription.java @@ -28,7 +28,7 @@ public class RemoteRepositoryDescription { public static final RemoteRepositoryDescription MAVEN_CENTRAL = new RemoteRepositoryDescription( "central", "Maven Central repository", - "http://repo1.maven.org/maven2" + "https://repo1.maven.org/maven2" ); public static final RemoteRepositoryDescription JBOSS_COMMUNITY = new RemoteRepositoryDescription( "jboss.community", diff --git a/java/openapi/src/icons/OpenapiIcons.java b/java/openapi/src/icons/OpenapiIcons.java new file mode 100644 index 000000000000..eb9eb75de85a --- /dev/null +++ b/java/openapi/src/icons/OpenapiIcons.java @@ -0,0 +1,17 @@ +package icons; + +import com.intellij.openapi.util.IconLoader; + +import javax.swing.*; + +/** + * NOTE THIS FILE IS AUTO-GENERATED + * DO NOT EDIT IT BY HAND, run build/scripts/icons.gant instead + */ +public class OpenapiIcons { + private static Icon load(String path) { + return IconLoader.getIcon(path, OpenapiIcons.class); + } + + public static final Icon RepositoryLibraryLogo = load("/icons/repositoryLibraryLogo.png"); // 16x16 +} diff --git a/java/openapi/src/org/jetbrains/idea/maven/utils/library/RepositoryLibraryDescription.java b/java/openapi/src/org/jetbrains/idea/maven/utils/library/RepositoryLibraryDescription.java index 2153db6276c4..f5a0aef9f95c 100644 --- a/java/openapi/src/org/jetbrains/idea/maven/utils/library/RepositoryLibraryDescription.java +++ b/java/openapi/src/org/jetbrains/idea/maven/utils/library/RepositoryLibraryDescription.java @@ -18,8 +18,8 @@ package org.jetbrains.idea.maven.utils.library; import com.intellij.jarRepository.RemoteRepositoryDescription; import com.intellij.jarRepository.RepositoryLibraryDefinition; import com.intellij.openapi.roots.DependencyScope; -import com.intellij.openapi.util.IconLoader; import com.intellij.util.containers.HashMap; +import icons.OpenapiIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor; @@ -43,7 +43,7 @@ public class RepositoryLibraryDescription { @NotNull public static final String SnapshotVersionSuffix = "-SNAPSHOT"; - public static final Icon DEFAULT_ICON = IconLoader.getIcon("/icons/repositoryLibraryLogo.png"); + public static final Icon DEFAULT_ICON = OpenapiIcons.RepositoryLibraryLogo; private static volatile Map ourStaticallyDefinedLibraries; diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java index 08c456a9067e..f1d1f8ea7c28 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -19,6 +19,7 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.template.JavaCodeContextType; import com.intellij.codeInsight.template.TemplateContextType; import com.intellij.dupLocator.iterators.NodeIterator; +import com.intellij.dupLocator.util.NodeFilter; import com.intellij.ide.highlighter.JavaFileType; import com.intellij.lang.Language; import com.intellij.lang.java.JavaLanguage; @@ -39,8 +40,6 @@ import com.intellij.structuralsearch.impl.matcher.*; import com.intellij.structuralsearch.impl.matcher.compiler.GlobalCompilingVisitor; import com.intellij.structuralsearch.impl.matcher.compiler.JavaCompilingVisitor; import com.intellij.structuralsearch.impl.matcher.compiler.PatternCompiler; -import com.intellij.structuralsearch.impl.matcher.filters.JavaLexicalNodesFilter; -import com.intellij.structuralsearch.impl.matcher.filters.LexicalNodesFilter; import com.intellij.structuralsearch.plugin.replace.ReplaceOptions; import com.intellij.structuralsearch.plugin.replace.impl.ParameterInfo; import com.intellij.structuralsearch.plugin.replace.impl.ReplacementBuilder; @@ -51,6 +50,7 @@ import com.intellij.structuralsearch.plugin.ui.SearchContext; import com.intellij.structuralsearch.plugin.ui.UIUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; +import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -60,9 +60,16 @@ import java.util.*; * @author Eugene.Kudelevsky */ public class JavaStructuralSearchProfile extends StructuralSearchProfile { - private JavaLexicalNodesFilter myJavaLexicalNodesFilter; - public String getText(PsiElement match, int start,int end) { + private static final Set PRIMITIVE_TYPES = new THashSet<>(Arrays.asList( + PsiKeyword.SHORT, PsiKeyword.BOOLEAN, + PsiKeyword.DOUBLE, PsiKeyword.LONG, + PsiKeyword.INT, PsiKeyword.FLOAT, + PsiKeyword.CHAR, PsiKeyword.BYTE + )); + + @Override + public String getText(PsiElement match, int start, int end) { if (match instanceof PsiIdentifier) { PsiElement parent = match.getParent(); if (parent instanceof PsiJavaCodeReferenceElement && !(parent instanceof PsiExpression)) { @@ -74,6 +81,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { return matchText.substring(start,end == -1? matchText.length():end); } + @Override public Class getElementContextByPsi(PsiElement element) { if (element instanceof PsiIdentifier) { element = element.getParent(); @@ -86,6 +94,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { } } + @Override @NotNull public String getTypedVarString(final PsiElement element) { String text; @@ -187,10 +196,12 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { return element; } + @Override public void compile(PsiElement[] elements, @NotNull GlobalCompilingVisitor globalVisitor) { elements[0].getParent().accept(new JavaCompilingVisitor(globalVisitor)); } + @Override @NotNull public PsiElementVisitor createMatchingVisitor(@NotNull GlobalMatchingVisitor globalVisitor) { return new JavaMatchingVisitor(globalVisitor); @@ -198,18 +209,30 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { @NotNull @Override - public PsiElementVisitor getLexicalNodesFilter(@NotNull LexicalNodesFilter filter) { - if (myJavaLexicalNodesFilter == null) { - myJavaLexicalNodesFilter = new JavaLexicalNodesFilter(filter); - } - return myJavaLexicalNodesFilter; + public NodeFilter getLexicalNodesFilter() { + return element -> isLexicalNode(element); } + private static boolean isLexicalNode(PsiElement element) { + if (element instanceof PsiWhiteSpace) { + return true; + } + else if (element instanceof PsiJavaToken) { + // do not filter out type keyword of new primitive arrays (e.g. int in new int[10]) + return !(element instanceof PsiKeyword && + PRIMITIVE_TYPES.contains(element.getText()) && + element.getParent() instanceof PsiNewExpression); + } + return false; + } + + @Override @NotNull public CompiledPattern createCompiledPattern() { return new JavaCompiledPattern(); } + @Override public boolean isMyLanguage(@NotNull Language language) { return language == JavaLanguage.INSTANCE; } @@ -385,6 +408,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { return JavaCodeContextType.class; } + @Override public PsiCodeFragment createCodeFragment(Project project, String text, PsiElement context) { final JavaCodeFragmentFactory factory = JavaCodeFragmentFactory.getInstance(project); return factory.createCodeBlockCodeFragment(text, context, true); diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java index fd7228b3c07c..750216d34074 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,6 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.structuralsearch.MatchOptions; import com.intellij.structuralsearch.MatchResult; -import com.intellij.structuralsearch.impl.matcher.filters.LexicalNodesFilter; import com.intellij.structuralsearch.impl.matcher.handlers.MatchPredicate; import com.intellij.structuralsearch.impl.matcher.handlers.MatchingHandler; import com.intellij.structuralsearch.impl.matcher.handlers.SubstitutionHandler; @@ -1547,12 +1546,8 @@ public class JavaMatchingVisitor extends JavaElementVisitor { final PsiElement element = PsiTreeUtil.getNextSiblingOfType(newKeyword, PsiWhiteSpace.class); if (element != null && element.getNextSibling() instanceof PsiKeyword) { - ((LexicalNodesFilter)LexicalNodesFilter.getInstance()).setCareKeyWords(true); - myMatchingVisitor.setResult(myMatchingVisitor.match(classReference, element.getNextSibling()) && myMatchingVisitor.matchSons(new1.getArrayInitializer(), new2.getArrayInitializer())); - - ((LexicalNodesFilter)LexicalNodesFilter.getInstance()).setCareKeyWords(false); if (myMatchingVisitor.getResult()) { // matching dims matchArrayDims(new1, new2); @@ -1565,9 +1560,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { if (classReference == new2.getClassReference()) { // probably anonymous class or array of primitive type - ((LexicalNodesFilter)LexicalNodesFilter.getInstance()).setCareKeyWords(true); myMatchingVisitor.setResult(myMatchingVisitor.matchSons(new1, new2)); - ((LexicalNodesFilter)LexicalNodesFilter.getInstance()).setCareKeyWords(false); } else if (new1.getAnonymousClass() == null && classReference != null && diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/AnnotationFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/AnnotationFilter.java index 82cb4baadb20..0fb11445bbad 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/AnnotationFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/AnnotationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -24,17 +24,16 @@ import com.intellij.psi.PsiElement; */ public class AnnotationFilter implements NodeFilter { - private static class NodeFilterHolder { - private static final NodeFilter instance = new AnnotationFilter(); - } - - public static NodeFilter getInstance() { - return NodeFilterHolder.instance; - } + private static final NodeFilter INSTANCE = new AnnotationFilter(); private AnnotationFilter() {} + @Override public boolean accepts(PsiElement element) { return element instanceof PsiAnnotation; } + + public static NodeFilter getInstance() { + return INSTANCE; + } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/BlockFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/BlockFilter.java index 5cef7ffaf3c8..eb6cc8a07fe7 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/BlockFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/BlockFilter.java @@ -1,7 +1,21 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; -import com.intellij.psi.JavaElementVisitor; import com.intellij.psi.PsiBlockStatement; import com.intellij.psi.PsiCodeBlock; import com.intellij.psi.PsiElement; @@ -9,34 +23,18 @@ import com.intellij.psi.PsiElement; /** * Filters block related nodes */ -public class BlockFilter extends JavaElementVisitor implements NodeFilter { - protected boolean result; +public class BlockFilter implements NodeFilter { + private static final NodeFilter INSTANCE = new BlockFilter(); + + private BlockFilter() {} + + @Override public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; - } - - @Override - public void visitBlockStatement(PsiBlockStatement psiBlockStatement) { - result = true; - } - - @Override - public void visitCodeBlock(PsiCodeBlock psiCodeBlock) { - result = true; - } - - private BlockFilter() { - } - - private static class NodeFilterHolder { - private static final NodeFilter instance = new BlockFilter(); + return element instanceof PsiBlockStatement || element instanceof PsiCodeBlock; } public static NodeFilter getInstance() { - return NodeFilterHolder.instance; + return INSTANCE; } - } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/ClassFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/ClassFilter.java index 6e68b08d70da..2b98a124ec10 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/ClassFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/ClassFilter.java @@ -1,8 +1,21 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; -import com.intellij.psi.JavaElementVisitor; -import com.intellij.psi.PsiAnonymousClass; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; @@ -13,31 +26,18 @@ import com.intellij.psi.PsiElement; * Time: 19:37:13 * To change this template use Options | File Templates. */ -public class ClassFilter extends JavaElementVisitor implements NodeFilter { - protected boolean result; +public class ClassFilter implements NodeFilter { - @Override public void visitAnonymousClass(PsiAnonymousClass psiAnonymousClass) { - result = true; - } + private static final NodeFilter INSTANCE = new ClassFilter(); - @Override public void visitClass(PsiClass psiClass) { - result = true; - } + private ClassFilter() {} - private static class NodeFilterHolder { - private static final NodeFilter instance = new ClassFilter(); + @Override + public boolean accepts(PsiElement element) { + return element instanceof PsiClass; } public static NodeFilter getInstance() { - return NodeFilterHolder.instance; - } - - private ClassFilter() { - } - - public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; + return INSTANCE; } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/CommentFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/CommentFilter.java index c2d974c9754e..8e2dbea55c40 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/CommentFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/CommentFilter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; @@ -10,39 +25,18 @@ import com.intellij.psi.*; * Time: 9:13:12 PM * To change this template use File | Settings | File Templates. */ -public class CommentFilter extends JavaElementVisitor implements NodeFilter { - protected boolean result; +public class CommentFilter implements NodeFilter { - @Override public void visitComment(PsiComment comment) { - result = true; - } + private static final NodeFilter INSTANCE = new CommentFilter(); - @Override public void visitField(PsiField field) { - result = true; - } + private CommentFilter() {} - @Override public void visitMethod(PsiMethod method) { - result = true; - } - - @Override public void visitClass(PsiClass clazz) { - result = true; - } - - private static class NodeFilterHolder { - private static final NodeFilter instance = new CommentFilter(); + @Override + public boolean accepts(PsiElement element) { + return element instanceof PsiComment || element instanceof PsiClass || element instanceof PsiMethod || element instanceof PsiField; } public static NodeFilter getInstance() { - return NodeFilterHolder.instance; - } - - private CommentFilter() { - } - - public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; + return INSTANCE; } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/ConstantFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/ConstantFilter.java index 401e3c15e365..bc348b0c09a0 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/ConstantFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/ConstantFilter.java @@ -1,7 +1,21 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; -import com.intellij.psi.JavaElementVisitor; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiLiteralExpression; @@ -12,27 +26,18 @@ import com.intellij.psi.PsiLiteralExpression; * Time: 7:55:40 PM * To change this template use File | Settings | File Templates. */ -public class ConstantFilter extends JavaElementVisitor implements NodeFilter { - protected boolean result; +public class ConstantFilter implements NodeFilter { - @Override public void visitLiteralExpression(PsiLiteralExpression psiLiteral) { - result = true; - } + private static final NodeFilter INSTANCE = new ConstantFilter(); - private static class NodeFilterHolder { - private static final NodeFilter instance = new ConstantFilter(); + private ConstantFilter() {} + + @Override + public boolean accepts(PsiElement element) { + return element instanceof PsiLiteralExpression; } public static NodeFilter getInstance() { - return NodeFilterHolder.instance; - } - - private ConstantFilter() { - } - - public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; + return INSTANCE; } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/DeclarationFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/DeclarationFilter.java index d5f5ef5bf36e..0cd9f7c7ac58 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/DeclarationFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/DeclarationFilter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; @@ -10,35 +25,18 @@ import com.intellij.psi.*; * Time: 19:23:24 * To change this template use Options | File Templates. */ -public class DeclarationFilter extends JavaElementVisitor implements NodeFilter { - protected boolean result; +public class DeclarationFilter implements NodeFilter { - @Override public void visitDeclarationStatement(PsiDeclarationStatement dcl) { - result = true; - } + private static final NodeFilter INSTANCE = new DeclarationFilter(); - @Override public void visitVariable(PsiVariable psiVar) { - result = true; - } + private DeclarationFilter() {} - @Override public void visitClass(PsiClass psiClass) { - result = true; - } - - private static class NodeFilterHolder { - private static final NodeFilter instance = new DeclarationFilter(); + @Override + public boolean accepts(PsiElement element) { + return element instanceof PsiDeclarationStatement || element instanceof PsiVariable || element instanceof PsiClass; } public static NodeFilter getInstance() { - return NodeFilterHolder.instance; - } - - private DeclarationFilter() { - } - - public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; + return INSTANCE; } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/ExpressionFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/ExpressionFilter.java index 632cc403eabb..616e9cdef336 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/ExpressionFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/ExpressionFilter.java @@ -1,39 +1,39 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; -import com.intellij.psi.JavaElementVisitor; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiExpression; -import com.intellij.psi.PsiReferenceExpression; /** * Filters expression nodes */ -public class ExpressionFilter extends JavaElementVisitor implements NodeFilter { - protected boolean result; +public class ExpressionFilter implements NodeFilter { - @Override public void visitReferenceExpression(PsiReferenceExpression psiReferenceExpression) { - result = true; - } - - @Override public void visitExpression(PsiExpression psiExpression) { - result = true; - } - - private static class NodeFilterHolder { - private static final NodeFilter instance = new ExpressionFilter(); - } + private static final NodeFilter INSTANCE = new ExpressionFilter(); public static NodeFilter getInstance() { - return NodeFilterHolder.instance; + return INSTANCE; } - private ExpressionFilter() { - } + private ExpressionFilter() {} + @Override public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; + return element instanceof PsiExpression; } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/JavaDocFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/JavaDocFilter.java index 0499f5469d57..eac2c1a4c616 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/JavaDocFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/JavaDocFilter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; @@ -14,18 +29,16 @@ import com.intellij.psi.javadoc.PsiDocComment; */ public class JavaDocFilter implements NodeFilter { + private static final NodeFilter INSTANCE = new JavaDocFilter(); + + private JavaDocFilter() {} + + @Override public boolean accepts(PsiElement element) { return element instanceof PsiDocCommentOwner || element instanceof PsiDocComment; } - private static class NodeFilterHolder { - private static final NodeFilter instance = new JavaDocFilter(); - } - public static NodeFilter getInstance() { - return NodeFilterHolder.instance; - } - - private JavaDocFilter() { + return INSTANCE; } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/JavaLexicalNodesFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/JavaLexicalNodesFilter.java deleted file mode 100644 index 2e190b7063a5..000000000000 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/JavaLexicalNodesFilter.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.structuralsearch.impl.matcher.filters; - -import com.intellij.psi.*; -import com.intellij.psi.javadoc.PsiDocComment; - -/** -* @author Eugene.Kudelevsky -*/ -public class JavaLexicalNodesFilter extends JavaElementVisitor { - private final LexicalNodesFilter myLexicalNodesFilter; - - public JavaLexicalNodesFilter(LexicalNodesFilter lexicalNodesFilter) { - this.myLexicalNodesFilter = lexicalNodesFilter; - } - - @Override public void visitJavaToken(final PsiJavaToken t) { - myLexicalNodesFilter.setResult(true); - } - - @Override public void visitComment(final PsiComment comment) { - } - - @Override public void visitDocComment(final PsiDocComment comment) { - } - - @Override public void visitKeyword(PsiKeyword keyword) { - myLexicalNodesFilter.setResult(!myLexicalNodesFilter.isCareKeyWords()); - } - - @Override public void visitWhiteSpace(final PsiWhiteSpace space) { - myLexicalNodesFilter.setResult(true); - } - - @Override public void visitErrorElement(final PsiErrorElement element) { - } -} diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/MethodFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/MethodFilter.java index 00888bb86c5a..1592181dd7b6 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/MethodFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/MethodFilter.java @@ -1,33 +1,39 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; -import com.intellij.psi.JavaElementVisitor; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; /** * Filters method nodes */ -public class MethodFilter extends JavaElementVisitor implements NodeFilter { - protected boolean result; +public class MethodFilter implements NodeFilter { - @Override public void visitMethod(PsiMethod psiMethod) { - result = true; - } + private static final NodeFilter INSTANCE = new MethodFilter(); private MethodFilter() {} - private static class NodeFilterHolder { - private static final NodeFilter instance = new MethodFilter(); + @Override + public boolean accepts(PsiElement element) { + return element instanceof PsiMethod; } public static NodeFilter getInstance() { - return NodeFilterHolder.instance; - } - - public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; + return INSTANCE; } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/StatementFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/StatementFilter.java index 91abc96139e1..87beb0e148bc 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/StatementFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/StatementFilter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; @@ -10,24 +25,14 @@ import com.intellij.psi.*; * Time: 17:46:10 * To change this template use Options | File Templates. */ -public class StatementFilter extends JavaElementVisitor implements NodeFilter { - protected boolean result; - - @Override public void visitReferenceExpression(PsiReferenceExpression psiReferenceExpression) { - result = false; - } - - @Override public void visitStatement(PsiStatement psiStatement) { - result = true; - } - - @Override public void visitComment(PsiComment comment) { - result = true; - } +public class StatementFilter implements NodeFilter { + @Override public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; + if (element instanceof PsiComment && element.getParent() instanceof PsiCodeBlock) { + // only allow comments in statement context + return true; + } + return element instanceof PsiStatement; } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/SymbolNodeFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/SymbolNodeFilter.java index 3e461b6738b6..9e74d360064e 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/SymbolNodeFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/SymbolNodeFilter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; @@ -7,66 +22,19 @@ import com.intellij.psi.*; * Tree filter for searching symbols ('T) */ public class SymbolNodeFilter extends JavaElementVisitor implements NodeFilter { - private boolean result; - @Override public void visitExpression(PsiExpression expr) { - result = true; - } + private static final NodeFilter INSTANCE = new SymbolNodeFilter(); - @Override public void visitLiteralExpression(PsiLiteralExpression psiLiteralExpression) { - result = true; - } + private SymbolNodeFilter() {} - @Override public void visitReferenceExpression(PsiReferenceExpression psiReferenceExpression) { - result = true; - } - - @Override public void visitAnnotation(final PsiAnnotation annotation) { - result = true; - } - - @Override public void visitAnnotationMethod(final PsiAnnotationMethod method) { - result = true; - } - - @Override public void visitNameValuePair(final PsiNameValuePair pair) { - result = true; - } - - @Override public void visitMethod(PsiMethod psiMethod) { - result = true; - } - - @Override public void visitClass(PsiClass psiClass) { - result = true; - } - - @Override public void visitReferenceElement(PsiJavaCodeReferenceElement psiJavaCodeReferenceElement) { - result = true; - } - - @Override public void visitVariable(PsiVariable psiVar) { - result = true; - } - - @Override public void visitTypeParameter(PsiTypeParameter psiTypeParameter) { - result = true; - } - - private static class NodeFilterHolder { - private static final NodeFilter instance = new SymbolNodeFilter(); + @Override + public boolean accepts(PsiElement element) { + return element instanceof PsiExpression || element instanceof PsiAnnotation || element instanceof PsiClass || + element instanceof PsiMethod || element instanceof PsiVariable || element instanceof PsiJavaCodeReferenceElement || + element instanceof PsiNameValuePair; } public static NodeFilter getInstance() { - return NodeFilterHolder.instance; - } - - private SymbolNodeFilter() { - } - - public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; + return INSTANCE; } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/TypeFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/TypeFilter.java index 14dd452b0b7a..a2d4c5711f97 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/TypeFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/TypeFilter.java @@ -1,10 +1,25 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; -import com.intellij.psi.JavaElementVisitor; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiJavaCodeReferenceElement; +import com.intellij.psi.PsiTypeParameter; /** * Created by IntelliJ IDEA. @@ -13,30 +28,18 @@ import com.intellij.psi.PsiJavaCodeReferenceElement; * Time: 1:07:09 * To change this template use File | Settings | File Templates. */ -public class TypeFilter extends JavaElementVisitor implements NodeFilter { - protected boolean result; +public class TypeFilter implements NodeFilter { - @Override public void visitClass(PsiClass aClass) { - result = true; - } - - @Override public void visitReferenceElement(PsiJavaCodeReferenceElement psiMethod) { - result = true; - } + private static final NodeFilter INSTANCE = new TypeFilter(); private TypeFilter() {} - private static class NodeFilterHolder { - private static final NodeFilter instance = new TypeFilter(); + @Override + public boolean accepts(PsiElement element) { + return element instanceof PsiClass && !(element instanceof PsiTypeParameter) || element instanceof PsiJavaCodeReferenceElement; } public static NodeFilter getInstance() { - return NodeFilterHolder.instance; - } - - public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; + return INSTANCE; } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/TypeParameterFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/TypeParameterFilter.java index 2f81c8b3980f..f378721e38c5 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/TypeParameterFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/TypeParameterFilter.java @@ -1,7 +1,25 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; -import com.intellij.psi.*; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiJavaCodeReferenceElement; +import com.intellij.psi.PsiTypeElement; +import com.intellij.psi.PsiTypeParameter; /** * Created by IntelliJ IDEA. @@ -10,34 +28,18 @@ import com.intellij.psi.*; * Time: 1:06:23 * To change this template use Options | File Templates. */ -public class TypeParameterFilter extends JavaElementVisitor implements NodeFilter { - protected boolean result; +public class TypeParameterFilter implements NodeFilter { - @Override public void visitTypeElement(PsiTypeElement psiTypeElement) { - result = true; - } - - @Override public void visitTypeParameter(PsiTypeParameter psiTypeParameter) { - result = true; - } - - @Override public void visitReferenceElement(PsiJavaCodeReferenceElement psiJavaCodeReferenceElement) { - result = true; - } + private static final NodeFilter INSTANCE = new TypeParameterFilter(); private TypeParameterFilter() {} - private static class NodeFilterHolder { - private static final NodeFilter instance = new TypeParameterFilter(); + @Override + public boolean accepts(PsiElement element) { + return element instanceof PsiTypeElement || element instanceof PsiTypeParameter || element instanceof PsiJavaCodeReferenceElement; } public static NodeFilter getInstance() { - return NodeFilterHolder.instance; - } - - public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; + return INSTANCE; } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/TypedSymbolNodeFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/TypedSymbolNodeFilter.java index 4416b8b7db24..b3f4e681545d 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/TypedSymbolNodeFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/TypedSymbolNodeFilter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; @@ -6,39 +21,36 @@ import com.intellij.psi.*; /** * Filter for typed symbols */ -public class TypedSymbolNodeFilter extends JavaElementVisitor implements NodeFilter { - private boolean result; +public class TypedSymbolNodeFilter implements NodeFilter { - @Override public void visitMethod(PsiMethod psiMethod) { - result = psiMethod.hasTypeParameters(); - } + private static final NodeFilter INSTANCE = new TypedSymbolNodeFilter(); - @Override public void visitClass(PsiClass psiClass) { - result = psiClass.hasTypeParameters(); - } + private TypedSymbolNodeFilter() {} - @Override public void visitReferenceElement(PsiJavaCodeReferenceElement psiJavaCodeReferenceElement) { - result = psiJavaCodeReferenceElement.getParameterList().getTypeParameterElements().length > 0; - } - - @Override public void visitTypeParameter(PsiTypeParameter parameter) { - // we need this since TypeParameter instanceof PsiClass (?) - } - - private static class NodeFilterHolder { - private static final NodeFilter instance = new TypedSymbolNodeFilter(); + @Override + public boolean accepts(PsiElement element) { + if (element instanceof PsiClass) { + if (element instanceof PsiTypeParameter) { + return false; + } + final PsiClass aClass = (PsiClass)element; + return aClass.hasTypeParameters(); + } + else if (element instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)element; + return method.hasTypeParameters(); + } + else if (element instanceof PsiJavaCodeReferenceElement) { + final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)element; + final PsiReferenceParameterList parameterList = referenceElement.getParameterList(); + if (parameterList != null) { + return parameterList.getTypeParameterElements().length > 0; + } + } + return false; } public static NodeFilter getInstance() { - return NodeFilterHolder.instance; - } - - private TypedSymbolNodeFilter() { - } - - public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; + return INSTANCE; } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/VariableFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/VariableFilter.java index e1907ecaf556..7ece0f2bd0a3 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/VariableFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/VariableFilter.java @@ -1,9 +1,22 @@ +/* + * Copyright 2000-2017 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.structuralsearch.impl.matcher.filters; import com.intellij.dupLocator.util.NodeFilter; -import com.intellij.psi.JavaElementVisitor; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiReferenceExpression; import com.intellij.psi.PsiVariable; /** @@ -13,29 +26,18 @@ import com.intellij.psi.PsiVariable; * Time: 19:52:57 * To change this template use Options | File Templates. */ -public class VariableFilter extends JavaElementVisitor implements NodeFilter { - protected boolean result; +public class VariableFilter implements NodeFilter { - public void visitReferenceExpression(final PsiReferenceExpression expression) { - } - - @Override public void visitVariable(PsiVariable psiVariable) { - result = true; - } + private static final NodeFilter INSTANCE = new VariableFilter(); private VariableFilter() {} - private static class NodeFilterHolder { - private static final NodeFilter instance = new VariableFilter(); + @Override + public boolean accepts(PsiElement element) { + return element instanceof PsiVariable; } public static NodeFilter getInstance() { - return NodeFilterHolder.instance; - } - - public boolean accepts(PsiElement element) { - result = false; - if (element!=null) element.accept(this); - return result; + return INSTANCE; } } diff --git a/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java b/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java index f56fc0970fd5..5622bab38511 100644 --- a/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java +++ b/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java @@ -39,7 +39,6 @@ import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.process.ProcessOutputTypes; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ExecutionEnvironmentBuilder; -import com.intellij.execution.runners.ProgramRunner; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; @@ -142,12 +141,7 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas } protected void disposeSession(final DebuggerSession debuggerSession) throws InterruptedException, InvocationTargetException { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - debuggerSession.dispose(); - } - }); + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> debuggerSession.dispose()); } @Override @@ -261,15 +255,12 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas final RemoteConnection debugParameters = DebuggerManagerImpl.createDebugParameters(javaCommandLineState.getJavaParameters(), debuggerRunnerSettings, true); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - try { - debuggerSession[0] = attachVirtualMachine(javaCommandLineState, javaCommandLineState.getEnvironment(), debugParameters, false); - } - catch (ExecutionException e) { - fail(e.getMessage()); - } + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + try { + debuggerSession[0] = attachVirtualMachine(javaCommandLineState, javaCommandLineState.getEnvironment(), debugParameters, false); + } + catch (ExecutionException e) { + fail(e.getMessage()); } }); @@ -338,17 +329,14 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas final RemoteState remoteState = new RemoteStateState(myProject, remoteConnection); final DebuggerSession[] debuggerSession = new DebuggerSession[1]; - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - try { - debuggerSession[0] = attachVirtualMachine(remoteState, new ExecutionEnvironmentBuilder(myProject, DefaultDebugExecutor.getDebugExecutorInstance()) - .runProfile(new MockConfiguration()) - .build(), remoteConnection, pollConnection); - } - catch (ExecutionException e) { - fail(e.getMessage()); - } + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + try { + debuggerSession[0] = attachVirtualMachine(remoteState, new ExecutionEnvironmentBuilder(myProject, DefaultDebugExecutor.getDebugExecutorInstance()) + .runProfile(new MockConfiguration()) + .build(), remoteConnection, pollConnection); + } + catch (ExecutionException e) { + fail(e.getMessage()); } }); debuggerSession[0].getProcess().getProcessHandler().addProcessListener(new ProcessAdapter() { @@ -361,13 +349,10 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas } protected void createBreakpoints(final String className) { - final PsiFile psiFile = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiFile compute() { - PsiClass psiClass = JavaPsiFacade.getInstance(myProject).findClass(className, GlobalSearchScope.allScope(myProject)); - assertNotNull(psiClass); - return psiClass.getContainingFile(); - } + final PsiFile psiFile = ApplicationManager.getApplication().runReadAction((Computable)() -> { + PsiClass psiClass = JavaPsiFacade.getInstance(myProject).findClass(className, GlobalSearchScope.allScope(myProject)); + assertNotNull(psiClass); + return psiClass.getContainingFile(); }); createBreakpoints(psiFile); @@ -441,12 +426,7 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas public DebuggerContextImpl createDebuggerContext(final SuspendContextImpl suspendContext, StackFrameProxyImpl stackFrame) { final DebuggerSession[] session = new DebuggerSession[1]; - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - session[0] = DebuggerManagerEx.getInstanceEx(myProject).getSession(suspendContext.getDebugProcess()); - } - }); + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> session[0] = DebuggerManagerEx.getInstanceEx(myProject).getSession(suspendContext.getDebugProcess())); DebuggerContextImpl debuggerContext = DebuggerContextImpl.createDebuggerContext( session[0], @@ -532,7 +512,7 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas @Override public ConfigurationFactory getFactory() { - return null; + return UnknownConfigurationType.FACTORY; } @Override @@ -549,32 +529,11 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas return null; } - @Override - @NotNull - public ConfigurationType getType() { - return UnknownConfigurationType.INSTANCE; - } - - @Override - public ConfigurationPerRunnerSettings createRunnerSettings(ConfigurationInfoProvider provider) { - return null; - } - - @Override - public SettingsEditor getRunnerSettingsEditor(ProgramRunner runner) { - return null; - } - @Override public RunConfiguration clone() { return null; } - @Override - public int getUniqueID() { - return 0; - } - @Override public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException { return null; @@ -585,9 +544,6 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas return ""; } - @Override - public void checkConfiguration() throws RuntimeConfigurationException { } - @Override public void readExternal(Element element) throws InvalidDataException { } diff --git a/java/testFramework/src/com/intellij/testFramework/InspectionTestCase.java b/java/testFramework/src/com/intellij/testFramework/InspectionTestCase.java index 5ad8b8655f5b..5f384c27294e 100644 --- a/java/testFramework/src/com/intellij/testFramework/InspectionTestCase.java +++ b/java/testFramework/src/com/intellij/testFramework/InspectionTestCase.java @@ -62,7 +62,7 @@ public abstract class InspectionTestCase extends PsiTestCase { private EntryPoint myUnusedCodeExtension; private VirtualFile ext_src; - protected static GlobalInspectionToolWrapper getUnusedDeclarationWrapper() { + public static GlobalInspectionToolWrapper getUnusedDeclarationWrapper() { InspectionEP ep = new InspectionEP(); ep.presentation = UnusedDeclarationPresentation.class.getName(); ep.implementationClass = UnusedDeclarationInspection.class.getName(); diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/OutputFileObject.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/OutputFileObject.java index 2c3b103b1cd6..0a93a947f9ad 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/OutputFileObject.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/OutputFileObject.java @@ -143,6 +143,12 @@ public final class OutputFileObject extends SimpleJavaFileObject { return FileUtilRt.loadFile(myFile, encoding, false); } + @Override + public Writer openWriter() throws IOException { + final String encoding = myEncodingName; + return encoding != null? new OutputStreamWriter(openOutputStream(), encoding) : super.openWriter(); + } + @Nullable public BinaryContent getContent() { return myContent; diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java index 0e30f9c371b7..a447538a0eff 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java @@ -196,7 +196,7 @@ final class JavacReferenceCollectorListener implements TaskListener { // member import for (Element memberElement : myElementUtility.getAllMembers((TypeElement)ownerElement)) { if (memberElement.getSimpleName() == name) { - incrementOrAdd(elements, JavacRef.JavacElementRefBase.fromElement(memberElement, myNameTableCache)); + incrementOrAdd(elements, JavacRef.JavacElementRefBase.fromElement(memberElement, null, myNameTableCache)); } } } @@ -213,7 +213,7 @@ final class JavacReferenceCollectorListener implements TaskListener { for (Element element = baseImport; element != null && element.getKind() != ElementKind.PACKAGE; element = element.getEnclosingElement()) { - incrementOrAdd(collector, JavacRef.JavacElementRefBase.fromElement(element, myNameTableCache)); + incrementOrAdd(collector, JavacRef.JavacElementRefBase.fromElement(element, null, myNameTableCache)); } } @@ -243,13 +243,18 @@ final class JavacReferenceCollectorListener implements TaskListener { @Nullable JavacRef.JavacElementRefBase asJavacRef(Element element) { - return JavacRef.JavacElementRefBase.fromElement(element, myNameTableCache); + return asJavacRef(element, null); + } + + @Nullable + JavacRef.JavacElementRefBase asJavacRef(Element element, Element qualifier) { + return JavacRef.JavacElementRefBase.fromElement(element, qualifier, myNameTableCache); } @Nullable JavacRef.JavacElementRefBase asJavacRef(TypeMirror typeMirror) { final Element element = getTypeUtility().asElement(typeMirror); - return element == null ? null : JavacRef.JavacElementRefBase.fromElement(element, myNameTableCache); + return element == null ? null : JavacRef.JavacElementRefBase.fromElement(element, null, myNameTableCache); } Element getReferencedElement(Tree tree) { diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacTreeRefScanner.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacTreeRefScanner.java index db00962cd1f9..6587fbe64b04 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacTreeRefScanner.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacTreeRefScanner.java @@ -15,12 +15,14 @@ */ package org.jetbrains.jps.javac.ast; +import com.intellij.util.containers.Stack; import com.sun.source.tree.*; import com.sun.source.util.TreeScanner; import org.jetbrains.jps.javac.ast.api.JavacDef; import org.jetbrains.jps.javac.ast.api.JavacRef; import javax.lang.model.element.*; +import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import java.util.EnumSet; @@ -87,7 +89,13 @@ class JavacTreeRefScanner extends TreeScanner modifiers = element.getModifiers(); + if (!modifiers.contains(Modifier.STATIC) && !modifiers.contains(Modifier.PRIVATE)) { + TypeElement currentClass = myCurrentEnclosingElement.peek(); + TypeElement actualQualifier = findQualifier(element, currentClass); + //means java.lang.Object's method called from an interface + if (actualQualifier == null) { + actualQualifier = myCurrentEnclosingElement.peek(); + } + collector.sinkReference(collector.asJavacRef(element, actualQualifier)); + scan(node.getTypeArguments(), collector); + scan(node.getArguments(), collector); + return null; + } + } + } + return super.visitMethodInvocation(node, collector); + } + + final Stack myCurrentEnclosingElement = new Stack(1); @Override public Tree visitClass(ClassTree node, JavacReferenceCollectorListener.ReferenceCollector refCollector) { TypeElement element = (TypeElement)refCollector.getReferencedElement(node); if (element == null) return null; + myCurrentEnclosingElement.add(element); final TypeMirror superclass = element.getSuperclass(); final List interfaces = element.getInterfaces(); @@ -136,7 +169,9 @@ class JavacTreeRefScanner extends TreeScanner interfaces = aClass.getInterfaces(); + for (TypeMirror type : interfaces) { + if (isTypeCorrespondsToElement(type, baseClass)) { + return true; + } + } + + if (isInheritorOrSelf(superType, baseClass)) return true; + + for (TypeMirror type : interfaces) { + if (isInheritorOrSelf(type, baseClass)) { + return true; + } + } + + return false; + } + + private static boolean isInheritorOrSelf(TypeMirror classType, TypeElement baseClass) { + if (classType != null && classType.getKind() != TypeKind.NONE) { + return isInheritorOrSelf((TypeElement)((DeclaredType) classType).asElement(), baseClass); + } + return false; + } + + private static boolean isTypeCorrespondsToElement(TypeMirror type, TypeElement baseClass) { + if (type != null && type.getKind() != TypeKind.NONE) { + DeclaredType superClass = (DeclaredType)type; + Element superClassElement = superClass.asElement(); + if (superClassElement == baseClass) return true; + } + return false; + } } diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/api/JavacRef.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/api/JavacRef.java index 2932091e2c42..ded777e6799d 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/api/JavacRef.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/api/JavacRef.java @@ -121,18 +121,15 @@ public interface JavacRef { abstract class JavacElementRefBase implements JavacRef { protected final @NotNull Element myOriginalElement; + @Nullable private final Element myQualifier; protected final JavacNameTable myNameTableCache; - protected JavacElementRefBase(@NotNull Element element, JavacNameTable nameTableCache) { + protected JavacElementRefBase(@NotNull Element element, @Nullable Element qualifier, JavacNameTable nameTableCache) { myOriginalElement = element; + myQualifier = qualifier; myNameTableCache = nameTableCache; } - @NotNull - public Element getOriginalElement() { - return myOriginalElement; - } - @NotNull @Override public String getName() { @@ -147,19 +144,19 @@ public interface JavacRef { @NotNull @Override public String getOwnerName() { - return myNameTableCache.parseBinaryName(myOriginalElement.getEnclosingElement()); + return myNameTableCache.parseBinaryName(myQualifier != null ? myQualifier : myOriginalElement.getEnclosingElement()); } @Nullable - public static JavacElementRefBase fromElement(Element element, JavacNameTable nameTableCache) { + public static JavacElementRefBase fromElement(Element element, Element qualifier, JavacNameTable nameTableCache) { if (element instanceof TypeElement) { - return new JavacElementClassImpl(element, nameTableCache); + return new JavacElementClassImpl(element, qualifier, nameTableCache); } else if (element instanceof VariableElement) { - return new JavacElementFieldImpl(element, nameTableCache); + return new JavacElementFieldImpl(element, qualifier, nameTableCache); } else if (element instanceof ExecutableElement) { - return new JavacElementMethodImpl(element, nameTableCache); + return new JavacElementMethodImpl(element, qualifier, nameTableCache); } else if (element == null || element.getKind() == ElementKind.OTHER || element.getKind() == ElementKind.TYPE_PARAMETER) { // javac reserved symbol kind (e.g: com.sun.tools.javac.comp.Resolve.ResolveError) @@ -175,18 +172,22 @@ public interface JavacRef { JavacElementRefBase base = (JavacElementRefBase)o; - return myOriginalElement == base.myOriginalElement; + return myOriginalElement == base.myOriginalElement && myQualifier == base.myQualifier; } @Override public int hashCode() { - return myOriginalElement.hashCode(); + int hashCode = myOriginalElement.hashCode(); + if (myQualifier != null) { + hashCode += myQualifier.hashCode(); + } + return hashCode; } } class JavacElementClassImpl extends JavacElementRefBase implements JavacClass { - public JavacElementClassImpl(@NotNull Element element, JavacNameTable nameTableCache) { - super(element, nameTableCache); + public JavacElementClassImpl(@NotNull Element element, @Nullable Element qualifier, JavacNameTable nameTableCache) { + super(element, qualifier, nameTableCache); } @NotNull @@ -202,8 +203,8 @@ public interface JavacRef { } class JavacElementMethodImpl extends JavacElementRefBase implements JavacMethod { - public JavacElementMethodImpl(@NotNull Element element, JavacNameTable nameTableCache) { - super(element, nameTableCache); + public JavacElementMethodImpl(@NotNull Element element, @Nullable Element qualifier, JavacNameTable nameTableCache) { + super(element, qualifier, nameTableCache); } @Override @@ -213,8 +214,8 @@ public interface JavacRef { } class JavacElementFieldImpl extends JavacElementRefBase implements JavacField { - public JavacElementFieldImpl(@NotNull Element element, JavacNameTable nameTableCache) { - super(element, nameTableCache); + public JavacElementFieldImpl(@NotNull Element element, @Nullable Element qualifier, JavacNameTable nameTableCache) { + super(element, qualifier, nameTableCache); } } } diff --git a/jps/jps-builders/src/defaultLogConfig.properties b/jps/jps-builders/src/defaultLogConfig.properties index 96da517cc67f..599f278a2147 100644 --- a/jps/jps-builders/src/defaultLogConfig.properties +++ b/jps/jps-builders/src/defaultLogConfig.properties @@ -1,4 +1,6 @@ log4j.rootLogger=info, file +#log4j.logger.org.jetbrains.jps=debug +#log4j.logger.#org.jetbrains.jps=debug log4j.appender.file=org.apache.log4j.RollingFileAppender log4j.appender.file.File=$LOG_FILE_PATH$ diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexUtil.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexUtil.java index 15b10c6f15d4..a8593634f934 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexUtil.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexUtil.java @@ -89,7 +89,8 @@ public class BackwardReferenceIndexUtil { try { lightRef = writer.enumerateNames(ref, name -> anonymousClassEnumerator.getLightRefIfAnonymous(name)); if (lightRef != null) { - convertedRefs.put(lightRef, count); + Integer old = convertedRefs.get(lightRef); + convertedRefs.put(lightRef, old == null ? count : (old + count)); } } catch (IOException e) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/CompilerBackwardReferenceIndex.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/CompilerBackwardReferenceIndex.java index 98de9c55c431..cc6c9dcf7a45 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/CompilerBackwardReferenceIndex.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/CompilerBackwardReferenceIndex.java @@ -169,13 +169,19 @@ public class CompilerBackwardReferenceIndex { try { final DataInputStream is = new DataInputStream(new FileInputStream(versionFile)); try { - return is.readInt() != CompilerIndices.VERSION; + int currentIndexVersion = is.readInt(); + boolean isDiffer = currentIndexVersion != CompilerIndices.VERSION; + if (isDiffer) { + LOG.info("backward reference index version differ, expected = " + CompilerIndices.VERSION + ", current = " + currentIndexVersion); + } + return isDiffer; } finally { is.close(); } } catch (IOException ignored) { + LOG.info("backward reference index version differ due to: " + ignored.getClass()); } return true; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ExternalProcessUtil.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ExternalProcessUtil.java index 04b1c2b1c5a1..6e609b9f9675 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ExternalProcessUtil.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/ExternalProcessUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package org.jetbrains.jps.incremental; import com.intellij.execution.CommandLineWrapperUtil; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.Nullable; @@ -31,7 +30,7 @@ import java.util.jar.Manifest; /** * @author Eugene Zhuravlev - * Date: 10/28/11 + * @since 28.10.2011 */ public class ExternalProcessUtil { private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.ExternalProcessUtil"); @@ -43,31 +42,11 @@ public class ExternalProcessUtil { try { aClass = Class.forName("com.intellij.rt.execution.CommandLineWrapper"); } - catch (Throwable ignored) { - } + catch (Throwable ignored) { } ourWrapperClass = aClass; } } - private static final char QUOTE = '\uEFEF'; - // please keep in sync with GeneralCommandLine.prepareCommand() - public static String prepareCommand(String parameter) { - if (SystemInfo.isWindows) { - if (parameter.contains("\"")) { - parameter = StringUtil.replace(parameter, "\"", "\\\""); - } - else if (parameter.length() == 0) { - parameter = "\"\""; - } - } - - if (parameter.length() >= 2 && parameter.charAt(0) == QUOTE && parameter.charAt(parameter.length() - 1) == QUOTE) { - parameter = '"' + parameter.substring(1, parameter.length() - 1) + '"'; - } - - return parameter; - } - public static List buildJavaCommandLine(String javaExecutable, String mainClass, List bootClasspath, @@ -78,11 +57,12 @@ public class ExternalProcessUtil { } public static List buildJavaCommandLine(String javaExecutable, - String mainClass, - List bootClasspath, - List classpath, - List vmParams, - List programParams, final boolean useCommandLineWrapper) { + String mainClass, + List bootClasspath, + List classpath, + List vmParams, + List programParams, + boolean useCommandLineWrapper) { return buildJavaCommandLine(javaExecutable, mainClass, bootClasspath, classpath, vmParams, programParams, useCommandLineWrapper, true); } @@ -91,14 +71,14 @@ public class ExternalProcessUtil { List bootClasspath, List classpath, List vmParams, - List programParams, final boolean useCommandLineWrapper, boolean useClasspathJar) { + List programParams, + boolean useCommandLineWrapper, + boolean useClasspathJar) { final List cmdLine = new ArrayList<>(); cmdLine.add(javaExecutable); - for (String param : vmParams) { - cmdLine.add(param); - } + cmdLine.addAll(vmParams); if (!bootClasspath.isEmpty()) { cmdLine.add("-bootclasspath"); @@ -108,33 +88,22 @@ public class ExternalProcessUtil { if (!classpath.isEmpty()) { List commandLineWrapperArgs = null; if (useCommandLineWrapper) { - final Class wrapperClass = getCommandLineWrapperClass(); + Class wrapperClass = getCommandLineWrapperClass(); if (wrapperClass != null) { try { if (useClasspathJar) { - final String classpathFile = CommandLineWrapperUtil.createClasspathJarFile(new Manifest(), classpath).getAbsolutePath(); - commandLineWrapperArgs = Arrays.asList( - "-classpath", - classpathFile - ); + String classpathFile = CommandLineWrapperUtil.createClasspathJarFile(new Manifest(), classpath).getAbsolutePath(); + commandLineWrapperArgs = Arrays.asList("-classpath", classpathFile); } else { File classpathFile = FileUtil.createTempFile("classpath", null); - final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(classpathFile))); - try { + try (PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(classpathFile)))) { for (String path : classpath) { writer.println(path); } } - finally { - writer.close(); - } commandLineWrapperArgs = Arrays.asList( - "-classpath", - ClasspathBootstrap.getResourcePath(wrapperClass), - wrapperClass.getName(), - classpathFile.getAbsolutePath() - ); + "-classpath", ClasspathBootstrap.getResourcePath(wrapperClass), wrapperClass.getName(), classpathFile.getAbsolutePath()); } } catch (IOException ex) { @@ -159,9 +128,7 @@ public class ExternalProcessUtil { // main class and params cmdLine.add(mainClass); - for (String param : programParams) { - cmdLine.add(param); - } + cmdLine.addAll(programParams); return cmdLine; } @@ -170,5 +137,4 @@ public class ExternalProcessUtil { private static Class getCommandLineWrapperClass() { return CommandLineWrapperClassHolder.ourWrapperClass; } - -} +} \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index ea712c9a3aaa..2342a70495af 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -22,9 +22,11 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileFilters; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ExceptionUtil; import com.intellij.util.SystemProperties; import com.intellij.util.concurrency.SequentialTaskExecutor; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.JBIterable; import com.intellij.util.execution.ParametersListUtil; import com.intellij.util.io.PersistentEnumeratorBase; import gnu.trove.THashMap; @@ -67,16 +69,16 @@ import org.jetbrains.jps.service.JpsServiceManager; import org.jetbrains.jps.service.SharedThreadPool; import javax.tools.*; -import java.io.*; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; import java.net.ServerSocket; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executor; import java.util.concurrent.Future; - -import static com.intellij.util.containers.ContainerUtil.concat; -import static com.intellij.util.containers.ContainerUtil.newArrayList; +import java.util.stream.Collectors; /** * @author Eugene Zhuravlev @@ -84,57 +86,49 @@ import static com.intellij.util.containers.ContainerUtil.newArrayList; */ public class JavaBuilder extends ModuleLevelBuilder { private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.java.JavaBuilder"); - public static final String BUILDER_NAME = "java"; private static final String JAVA_EXTENSION = "java"; - private static final Key JAVA_COMPILER_VERSION_KEY = GlobalContextKey.create("_java_compiler_version_"); + + public static final String BUILDER_NAME = "java"; public static final Key IS_ENABLED = Key.create("_java_compiler_enabled_"); - private static final Key PREFER_TARGT_JDK_COMPILER = GlobalContextKey.create("_prefer_target_jdk_javac_"); + public static final FileFilter JAVA_SOURCES_FILTER = FileFilters.withExtension(JAVA_EXTENSION); + + private static final Key JAVA_COMPILER_VERSION_KEY = GlobalContextKey.create("_java_compiler_version_"); + private static final Key PREFER_TARGET_JDK_COMPILER = GlobalContextKey.create("_prefer_target_jdk_javac_"); private static final Key COMPILING_TOOL = Key.create("_java_compiling_tool_"); private static final Key>> COMPILER_USAGE_STATISTICS = Key.create("_java_compiler_usage_stats_"); + private static final List COMPILABLE_EXTENSIONS = Collections.singletonList(JAVA_EXTENSION); - private static final Set FILTERED_OPTIONS = new HashSet<>(Collections.singletonList( - "-target" - )); - private static final Set FILTERED_SINGLE_OPTIONS = new HashSet<>(Arrays.asList( - "-g", "-deprecation", "-nowarn", "-verbose", "-proc:none", "-proc:only", "-proceedOnError" - )); + private static final Set FILTERED_OPTIONS = ContainerUtil.newHashSet( + "-target"); + private static final Set FILTERED_SINGLE_OPTIONS = ContainerUtil.newHashSet( + "-g", "-deprecation", "-nowarn", "-verbose", "-proc:none", "-proc:only", "-proceedOnError"); - public static final FileFilter JAVA_SOURCES_FILTER = FileFilters.withExtension(JAVA_EXTENSION); - private static final String RT_JAR_PATH_SUFFIX = File.separator + "rt.jar"; - - private final Executor myTaskRunner; private static final List ourClassProcessors = new ArrayList<>(); - private static final Set> ourCompilableModuleTypes; - @Nullable - private static final File ourDefaultRtJar; + private static final Set> ourCompilableModuleTypes = new HashSet<>(); + private static final @Nullable File ourDefaultRtJar; static { - ourCompilableModuleTypes = new HashSet<>(); for (JavaBuilderExtension extension : JpsServiceManager.getInstance().getExtensions(JavaBuilderExtension.class)) { ourCompilableModuleTypes.addAll(extension.getCompilableModuleTypes()); } + File rtJar = null; StringTokenizer tokenizer = new StringTokenizer(System.getProperty("sun.boot.class.path", ""), File.pathSeparator, false); while (tokenizer.hasMoreTokens()) { - final String path = tokenizer.nextToken(); - if (isRtJarPath(path)) { - rtJar = new File(path); + File file = new File(tokenizer.nextToken()); + if ("rt.jar".equals(file.getName())) { + rtJar = file; break; } } ourDefaultRtJar = rtJar; } - private static boolean isRtJarPath(String path) { - if (StringUtil.endsWithIgnoreCase(path, RT_JAR_PATH_SUFFIX)) { - return true; - } - return RT_JAR_PATH_SUFFIX.charAt(0) != '/' && StringUtil.endsWithIgnoreCase(path, "/rt.jar"); - } - public static void registerClassPostProcessor(ClassPostProcessor processor) { ourClassProcessors.add(processor); } + private final Executor myTaskRunner; + public JavaBuilder(Executor tasksExecutor) { super(BuilderCategory.TRANSLATOR); myTaskRunner = new SequentialTaskExecutor("JavaBuilder pool", tasksExecutor); @@ -199,7 +193,7 @@ public class JavaBuilder extends ModuleLevelBuilder { @Override public List getCompilableFileExtensions() { - return Collections.singletonList(JAVA_EXTENSION); + return COMPILABLE_EXTENSIONS; } @Override @@ -222,22 +216,25 @@ public class JavaBuilder extends ModuleLevelBuilder { try { final Set filesToCompile = new THashSet<>(FileUtil.FILE_HASHING_STRATEGY); - dirtyFilesHolder.processDirtyFiles(new FileProcessor() { - @Override - public boolean apply(ModuleBuildTarget target, File file, JavaSourceRootDescriptor descriptor) throws IOException { - if (JAVA_SOURCES_FILTER.accept(file) && ourCompilableModuleTypes.contains(target.getModule().getModuleType())) { - filesToCompile.add(file); - } - return true; + dirtyFilesHolder.processDirtyFiles((target, file, descriptor) -> { + if (JAVA_SOURCES_FILTER.accept(file) && ourCompilableModuleTypes.contains(target.getModule().getModuleType())) { + filesToCompile.add(file); } + return true; }); + + int javaModulesCount = 0; if ((!filesToCompile.isEmpty() || dirtyFilesHolder.hasRemovedFiles()) && JpsJavaSdkType.parseVersion(getLanguageLevel(ContainerUtil.getFirstItem(chunk.getModules()))) >= 9) { // at the moment, there is no incremental compilation for module-info files, so they should be rebuilt on every change JavaModuleIndex index = getJavaModuleIndex(context); - for (JpsModule module : chunk.getModules()) { - ContainerUtil.addIfNotNull(filesToCompile, index.getModuleInfoFile(module)); + for (ModuleBuildTarget target : chunk.getTargets()) { + File moduleInfoFile = index.getModuleInfoFile(target.getModule(), target.isTests()); + if (moduleInfoFile != null) { + filesToCompile.add(moduleInfoFile); + javaModulesCount++; + } } } @@ -248,7 +245,14 @@ public class JavaBuilder extends ModuleLevelBuilder { } } - return compile(context, chunk, dirtyFilesHolder, filesToCompile, outputConsumer, compilingTool); + if (javaModulesCount > 1) { + String prefix = "Cannot compile a module cycle with multiple module-info.java files: "; + String message = chunk.getModules().stream().map(JpsModule::getName).collect(Collectors.joining(", ", prefix, "")); + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, message)); + return ExitCode.ABORT; + } + + return compile(context, chunk, dirtyFilesHolder, filesToCompile, outputConsumer, compilingTool, javaModulesCount > 0); } catch (BuildDataCorruptedException | PersistentEnumeratorBase.CorruptedException | ProjectBuildException e) { throw e; @@ -256,17 +260,7 @@ public class JavaBuilder extends ModuleLevelBuilder { catch (Exception e) { LOG.info(e); String message = e.getMessage(); - if (message == null) { - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - final PrintStream stream = new PrintStream(out); - try { - e.printStackTrace(stream); - } - finally { - stream.close(); - } - message = "Internal error: \n" + out; - } + if (message == null) message = "Internal error: \n" + ExceptionUtil.getThrowableText(e); context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, message)); throw new StopBuildException(); } @@ -277,7 +271,8 @@ public class JavaBuilder extends ModuleLevelBuilder { DirtyFilesHolder dirtyFilesHolder, Collection files, OutputConsumer outputConsumer, - JavaCompilingTool compilingTool) throws Exception { + JavaCompilingTool compilingTool, + boolean hasModules) throws Exception { ExitCode exitCode = ExitCode.NOTHING_DONE; final boolean hasSourcesToCompile = !files.isEmpty(); @@ -330,7 +325,7 @@ public class JavaBuilder extends ModuleLevelBuilder { } } try { - compiledOk = compileJava(context, chunk, files, classpath, platformCp, srcPath, diagnosticSink, outputSink, compilingTool); + compiledOk = compileJava(context, chunk, files, classpath, platformCp, srcPath, diagnosticSink, outputSink, compilingTool, hasModules); } finally { // heuristic: incorrect paths data recovery, so that the next make should not contain non-existing sources in 'recompile' list @@ -377,7 +372,8 @@ public class JavaBuilder extends ModuleLevelBuilder { Collection sourcePath, DiagnosticOutputConsumer diagnosticSink, OutputFileConsumer outputSink, - JavaCompilingTool compilingTool) throws Exception { + JavaCompilingTool compilingTool, + boolean hasModules) throws Exception { final TasksCounter counter = new TasksCounter(); COUNTER_KEY.set(context, counter); @@ -402,7 +398,6 @@ public class JavaBuilder extends ModuleLevelBuilder { try { final int targetLanguageLevel = JpsJavaSdkType.parseVersion(getLanguageLevel(chunk.getModules().iterator().next())); final boolean shouldForkJavac = shouldForkCompilerProcess(context, chunk, targetLanguageLevel); - final boolean hasModules = targetLanguageLevel >= 9 && getJavaModuleIndex(context).hasJavaModules(modules); // when forking external javac, compilers from SDK 1.6 and higher are supported Pair forkSdk = null; @@ -419,7 +414,8 @@ public class JavaBuilder extends ModuleLevelBuilder { final List options = getCompilationOptions(compilerSdkVersion, context, chunk, profile, compilingTool); if (LOG.isDebugEnabled()) { - LOG.debug("Compiling chunk [" + chunk.getName() + "] with options: \"" + StringUtil.join(options, " ") + "\""); + String mode = shouldForkJavac ? "fork" : "in-process"; + LOG.debug("Compiling chunk [" + chunk.getName() + "] with options: \"" + StringUtil.join(options, " ") + "\", mode=" + mode); } Collection platformCp = calcEffectivePlatformCp(originalPlatformCp, options, compilingTool); @@ -444,7 +440,7 @@ public class JavaBuilder extends ModuleLevelBuilder { if (!platformCp.isEmpty()) { final int chunkSdkVersion; if (hasModules) { - modulePath = newArrayList(concat(platformCp, modulePath)); + modulePath = JBIterable.from(platformCp).append(modulePath).toList(); platformCp = Collections.emptyList(); } else if ((chunkSdkVersion = getChunkSdkVersion(chunk)) >= 9) { @@ -452,7 +448,7 @@ public class JavaBuilder extends ModuleLevelBuilder { // because platform classes are stored in jimage binary files with unknown format. // Because of this we are clearing platform classpath so that javac will resolve against its own boot classpath // and prepending additional jars from the JDK configuration to compilation classpath - classPath = newArrayList(concat(platformCp, classPath)); + classPath = JBIterable.from(platformCp).append(classPath).toList(); platformCp = Collections.emptyList(); } else if (shouldUseReleaseOption(context, compilerSdkVersion, chunkSdkVersion, targetLanguageLevel)) { @@ -485,7 +481,7 @@ public class JavaBuilder extends ModuleLevelBuilder { final ExternalJavacManager server = ensureJavacServerStarted(context); rc = server.forkJavac( forkSdk.getFirst(), - getExternalJavacHeapSize(context), + getExternalJavacHeapSize(), vmOptions, options, platformCp, classPath, modulePath, sourcePath, files, outs, diagnosticSink, classesConsumer, compilingTool, context.getCancelStatus() ); @@ -512,7 +508,7 @@ public class JavaBuilder extends ModuleLevelBuilder { } } - private static int getExternalJavacHeapSize(CompileContext context) { + private static int getExternalJavacHeapSize() { //final JpsProject project = context.getProjectDescriptor().getProject(); //final JpsJavaCompilerConfiguration config = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project); //final JpsJavaCompilerOptions options = config.getCurrentCompilerOptions(); @@ -599,13 +595,13 @@ public class JavaBuilder extends ModuleLevelBuilder { } private static boolean preferTargetJdkCompiler(CompileContext context) { - Boolean val = PREFER_TARGT_JDK_COMPILER.get(context); + Boolean val = PREFER_TARGET_JDK_COMPILER.get(context); if (val == null) { final JpsProject project = context.getProjectDescriptor().getProject(); final JpsJavaCompilerConfiguration config = JpsJavaExtensionService.getInstance().getCompilerConfiguration(project); // default val = config != null? config.getCompilerOptions(JavaCompilers.JAVAC_ID).PREFER_TARGET_JDK_COMPILER : Boolean.TRUE; - PREFER_TARGT_JDK_COMPILER.set(context, val); + PREFER_TARGET_JDK_COMPILER.set(context, val); } return val; } @@ -790,7 +786,7 @@ public class JavaBuilder extends ModuleLevelBuilder { chunk.getModules().iterator().next(), chunk.containsTests(), profile ); if (srcOutput != null) { - srcOutput.mkdirs(); + FileUtil.createDirectory(srcOutput); options.add("-s"); options.add(srcOutput.getPath()); } @@ -844,10 +840,11 @@ public class JavaBuilder extends ModuleLevelBuilder { final int targetLanguageLevel = JpsJavaSdkType.parseVersion(langLevel); if (shouldUseReleaseOption(context, compilerSdkVersion, chunkSdkVersion, targetLanguageLevel)) { - options.add(getReleaseOptionName()); + options.add("--release"); options.add(String.valueOf(targetLanguageLevel)); return; } + // using older -source, -target and -bootclasspath options if (!StringUtil.isEmpty(langLevel)) { options.add("-source"); @@ -908,26 +905,6 @@ public class JavaBuilder extends ModuleLevelBuilder { } } - // todo: after java9 release the method can be deleted - @NotNull - private static String getReleaseOptionName() { - final String versionString = System.getProperty("java.runtime.version", null); // should look kind of "9-ea+136" - if (versionString != null) { - final int start = versionString.indexOf("+"); - if (start > 0) { - try { - final int minorVersion = Integer.parseInt(versionString.substring(start + 1)); - if (minorVersion < 135) { - return "-release"; - } - } - catch (Throwable ignored) { - } - } - } - return "--release"; - } - private static String getLanguageLevel(JpsModule module) { final LanguageLevel level = JpsJavaExtensionService.getInstance().getLanguageLevel(module); return level != null ? level.getComplianceOption() : null; @@ -1314,4 +1291,4 @@ public class JavaBuilder extends ModuleLevelBuilder { } } } -} +} \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacManager.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacManager.java index 8f730fc9f83b..60bdf91a9486 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacManager.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -52,23 +52,23 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.*; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** * @author Eugene Zhuravlev - * Date: 1/22/12 + * @since 2.01.2012 */ -@SuppressWarnings("UseOfSystemOutOrSystemErr") public class ExternalJavacManager { private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.javac.ExternalJavacServer"); + public static final GlobalContextKey KEY = GlobalContextKey.create("_external_javac_server_"); - public static final int DEFAULT_SERVER_PORT = 7878; public static final String STDOUT_LINE_PREFIX = "JAVAC_PROCESS[STDOUT]"; public static final String STDERR_LINE_PREFIX = "JAVAC_PROCESS[STDERR]"; + private static final AttributeKey SESSION_DESCRIPTOR = AttributeKey.valueOf("ExternalJavacServer.JavacProcessDescriptor"); - @NotNull + private final File myWorkingDir; - @NotNull private final ChannelRegistrar myChannelRegistrar; private final Map myMessageHandlers = new HashMap<>(); private int myListenPort = DEFAULT_SERVER_PORT; @@ -78,26 +78,24 @@ public class ExternalJavacManager { myChannelRegistrar = new ChannelRegistrar(); } - @NotNull - public File getWorkingDir() { - return myWorkingDir; - } - public void start(int listenPort) { - final ServerBootstrap bootstrap = new ServerBootstrap().group(new NioEventLoopGroup(1, SharedThreadPool.getInstance())).channel(NioServerSocketChannel.class); - bootstrap.childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_KEEPALIVE, true); final ChannelHandler compilationRequestsHandler = new CompilationRequestsHandler(); - bootstrap.childHandler(new ChannelInitializer() { - @Override - protected void initChannel(Channel channel) throws Exception { - channel.pipeline().addLast(myChannelRegistrar, - new ProtobufVarint32FrameDecoder(), - new ProtobufDecoder(JavacRemoteProto.Message.getDefaultInstance()), - new ProtobufVarint32LengthFieldPrepender(), - new ProtobufEncoder(), - compilationRequestsHandler); - } - }); + final ServerBootstrap bootstrap = new ServerBootstrap() + .group(new NioEventLoopGroup(1, SharedThreadPool.getInstance())) + .channel(NioServerSocketChannel.class) + .childOption(ChannelOption.TCP_NODELAY, true) + .childOption(ChannelOption.SO_KEEPALIVE, true) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(Channel channel) throws Exception { + channel.pipeline().addLast(myChannelRegistrar, + new ProtobufVarint32FrameDecoder(), + new ProtobufDecoder(JavacRemoteProto.Message.getDefaultInstance()), + new ProtobufVarint32LengthFieldPrepender(), + new ProtobufEncoder(), + compilationRequestsHandler); + } + }); try { final InetAddress loopback = InetAddress.getByName(null); myChannelRegistrar.add(bootstrap.bind(loopback, listenPort).syncUninterruptibly().channel()); @@ -107,20 +105,24 @@ public class ExternalJavacManager { throw new RuntimeException(e); } } - - public boolean forkJavac(final String javaHome, final int heapSize, List vmOptions, List options, + public boolean forkJavac(String javaHome, + int heapSize, + List vmOptions, + List options, Collection platformCp, Collection classpath, Collection modulePath, Collection sourcePath, Collection files, Map> outs, - final DiagnosticOutputConsumer diagnosticSink, OutputFileConsumer outputSink, - final JavaCompilingTool compilingTool, - final CanceledStatus cancelStatus) { + DiagnosticOutputConsumer diagnosticSink, + OutputFileConsumer outputSink, + JavaCompilingTool compilingTool, + CanceledStatus cancelStatus) { final ExternalJavacMessageHandler rh = new ExternalJavacMessageHandler(diagnosticSink, outputSink, getEncodingName(options)); - final JavacRemoteProto.Message.Request request = JavacProtoUtil.createCompilationRequest(options, files, classpath, platformCp, modulePath, sourcePath, outs); + final JavacRemoteProto.Message.Request request = JavacProtoUtil.createCompilationRequest( + options, files, classpath, platformCp, modulePath, sourcePath, outs); final UUID uuid = UUID.randomUUID(); final JavacProcessDescriptor processDescriptor = new JavacProcessDescriptor(uuid, rh, request); synchronized (myMessageHandlers) { @@ -184,33 +186,29 @@ public class ExternalJavacManager { @Nullable private static String getEncodingName(List options) { - boolean found = false; - for (String option : options) { - if (found) { - return option; - } - if ("-encoding".equalsIgnoreCase(option)) { - found = true; - } - } - return null; + int p = options.indexOf("-encoding"); + return p >= 0 && p < options.size() - 1 ? options.get(p + 1) : null; } - + public void stop() { myChannelRegistrar.close().awaitUninterruptibly(); } - private ExternalJavacProcessHandler launchExternalJavacProcess(UUID uuid, String sdkHomePath, - int heapSize, - int port, - File workingDir, - List vmOptions, - JavaCompilingTool compilingTool) throws Exception { + private ExternalJavacProcessHandler launchExternalJavacProcess(UUID uuid, + String sdkHomePath, + int heapSize, + int port, + File workingDir, + List vmOptions, + JavaCompilingTool compilingTool) throws Exception { final List cmdLine = new ArrayList<>(); + appendParam(cmdLine, getVMExecutablePath(sdkHomePath)); + + appendParam(cmdLine, "-Djava.awt.headless=true"); + //appendParam(cmdLine, "-XX:MaxPermSize=150m"); //appendParam(cmdLine, "-XX:ReservedCodeCacheSize=64m"); - appendParam(cmdLine, "-Djava.awt.headless=true"); if (heapSize > 0) { // if the value is zero or negative, use JVM default memory settings final int xms = heapSize / 2; @@ -225,26 +223,12 @@ public class ExternalJavacManager { //appendParam(cmdLine, "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5009"); // javac's VM should use the same default locale that IDEA uses in order for javac to print messages in 'correct' language - final String encoding = System.getProperty("file.encoding"); - if (encoding != null) { - appendParam(cmdLine, "-Dfile.encoding=" + encoding); - } - final String lang = System.getProperty("user.language"); - if (lang != null) { - //noinspection HardCodedStringLiteral - appendParam(cmdLine, "-Duser.language=" + lang); - } - final String country = System.getProperty("user.country"); - if (country != null) { - //noinspection HardCodedStringLiteral - appendParam(cmdLine, "-Duser.country=" + country); - } - //noinspection HardCodedStringLiteral - final String region = System.getProperty("user.region"); - if (region != null) { - //noinspection HardCodedStringLiteral - appendParam(cmdLine, "-Duser.region=" + region); - } + copyProperty(cmdLine, "file.encoding"); + copyProperty(cmdLine, "user.language"); + copyProperty(cmdLine, "user.country"); + copyProperty(cmdLine, "user.region"); + + copyProperty(cmdLine, "io.netty.noUnsafe"); appendParam(cmdLine, "-D" + ExternalJavacProcess.JPS_JAVA_COMPILING_TOOL_PROPERTY + "=" + compilingTool.getId()); @@ -258,30 +242,23 @@ public class ExternalJavacManager { } appendParam(cmdLine, "-classpath"); - - final List cp = ClasspathBootstrap.getExternalJavacProcessClasspath(sdkHomePath, compilingTool); - final StringBuilder classpath = new StringBuilder(); - for (File file : cp) { - if (classpath.length() > 0) { - classpath.append(File.pathSeparator); - } - classpath.append(file.getPath()); - } - appendParam(cmdLine, classpath.toString()); + List cp = ClasspathBootstrap.getExternalJavacProcessClasspath(sdkHomePath, compilingTool); + appendParam(cmdLine, cp.stream().map(File::getPath).collect(Collectors.joining(File.pathSeparator))); appendParam(cmdLine, ExternalJavacProcess.class.getName()); appendParam(cmdLine, uuid.toString()); appendParam(cmdLine, "127.0.0.1"); appendParam(cmdLine, Integer.toString(port)); - workingDir.mkdirs(); - appendParam(cmdLine, FileUtil.toSystemIndependentName(workingDir.getPath())); - final ProcessBuilder builder = new ProcessBuilder(cmdLine); - builder.directory(workingDir); + if (LOG.isDebugEnabled()) { + LOG.debug("starting external compiler: " + cmdLine); + } - final Process process = builder.start(); + FileUtil.createDirectory(workingDir); + + Process process = new ProcessBuilder(cmdLine).directory(workingDir).start(); return createProcessHandler(process, StringUtil.join(cmdLine, " ")); } @@ -289,16 +266,23 @@ public class ExternalJavacManager { return new ExternalJavacProcessHandler(process, commandLine); } - private static void appendParam(List cmdLine, String param) { + private static void appendParam(List cmdLine, String parameter) { if (SystemInfo.isWindows) { - if (param.contains("\"")) { - param = StringUtil.replace(param, "\"", "\\\""); + if (parameter.contains("\"")) { + parameter = StringUtil.replace(parameter, "\"", "\\\""); } - else if (param.length() == 0) { - param = "\"\""; + else if (parameter.length() == 0) { + parameter = "\"\""; } } - cmdLine.add(param); + cmdLine.add(parameter); + } + + private static void copyProperty(List cmdLine, String name) { + String value = System.getProperty(name); + if (value != null) { + appendParam(cmdLine, "-D" + name + '=' + value); + } } private static String getVMExecutablePath(String sdkHome) { @@ -328,7 +312,7 @@ public class ExternalJavacManager { private class CompilationRequestsHandler extends SimpleChannelInboundHandler { @Override public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { - JavacProcessDescriptor descriptor = ctx.channel().attr(SESSION_DESCRIPTOR).getAndRemove(); + JavacProcessDescriptor descriptor = ctx.channel().attr(SESSION_DESCRIPTOR).getAndSet(null); if (descriptor != null) { descriptor.setDone(); } @@ -338,12 +322,12 @@ public class ExternalJavacManager { @Override public void channelRead0(final ChannelHandlerContext context, JavacRemoteProto.Message message) throws Exception { JavacProcessDescriptor descriptor = context.channel().attr(SESSION_DESCRIPTOR).get(); - + UUID sessionId; if (descriptor == null) { // this is the first message for this session, so fill session data with missing info sessionId = JavacProtoUtil.fromProtoUUID(message.getSessionId()); - + descriptor = myMessageHandlers.get(sessionId); if (descriptor != null) { descriptor.channel = context.channel(); @@ -353,7 +337,7 @@ public class ExternalJavacManager { else { sessionId = descriptor.sessionId; } - + final ExternalJavacMessageHandler handler = descriptor != null? descriptor.handler : null; final JavacRemoteProto.Message.Type messageType = message.getMessageType(); @@ -388,7 +372,7 @@ public class ExternalJavacManager { } finally { if (reply != null) { - context.channel().writeAndFlush(reply); + context.channel().writeAndFlush(reply); } } } @@ -436,15 +420,15 @@ public class ExternalJavacManager { } private static class JavacProcessDescriptor { - @NotNull - final UUID sessionId; - @NotNull - final ExternalJavacMessageHandler handler; - volatile JavacRemoteProto.Message.Request request; - volatile Channel channel; + private final UUID sessionId; + private final ExternalJavacMessageHandler handler; + private volatile JavacRemoteProto.Message.Request request; + private volatile Channel channel; private final Semaphore myDone = new Semaphore(); - public JavacProcessDescriptor(@NotNull UUID sessionId, @NotNull ExternalJavacMessageHandler handler, @NotNull JavacRemoteProto.Message.Request request) { + public JavacProcessDescriptor(@NotNull UUID sessionId, + @NotNull ExternalJavacMessageHandler handler, + @NotNull JavacRemoteProto.Message.Request request) { this.sessionId = sessionId; this.handler = handler; this.request = request; @@ -456,16 +440,13 @@ public class ExternalJavacManager { channel.writeAndFlush(JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createCancelRequest())); } } - + public void setDone() { myDone.up(); } - - + public boolean waitFor(long timeout) { return myDone.waitFor(timeout); } - } - } \ No newline at end of file diff --git a/jps/jps-builders/testData/referencesIndex/qualifierResolution/Foo.java b/jps/jps-builders/testData/referencesIndex/qualifierResolution/Foo.java new file mode 100644 index 000000000000..172f788d4e38 --- /dev/null +++ b/jps/jps-builders/testData/referencesIndex/qualifierResolution/Foo.java @@ -0,0 +1,9 @@ +class Foo { + + void m(ArrayListImpl l) { + l.size(); + } + +} + +class ArrayListImpl extends java.util.ArrayList {} \ No newline at end of file diff --git a/jps/jps-builders/testData/referencesIndex/qualifierResolution/initialIndex.txt b/jps/jps-builders/testData/referencesIndex/qualifierResolution/initialIndex.txt new file mode 100644 index 000000000000..fd10dfc28c62 --- /dev/null +++ b/jps/jps-builders/testData/referencesIndex/qualifierResolution/initialIndex.txt @@ -0,0 +1,18 @@ +Backward Hierarchy: +java.lang.Object -> Foo +java.util.ArrayList -> ArrayListImpl + +Backward References: +ArrayListImpl in Foo occurrences = 2 +ArrayListImpl.(0) in Foo occurrences = 1 +ArrayListImpl.size(0) in Foo occurrences = 1 +Foo in Foo occurrences = 1 +Foo.(0) in Foo occurrences = 1 +Foo.m(1) in Foo occurrences = 1 +java.lang.Object.(0) in Foo occurrences = 1 +java.util.ArrayList in Foo occurrences = 1 +java.util.ArrayList.(0) in Foo occurrences = 1 + +Class Definitions: +ArrayListImpl in Foo +Foo in Foo \ No newline at end of file diff --git a/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution/Foo.java b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution/Foo.java new file mode 100644 index 000000000000..be60919d371e --- /dev/null +++ b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution/Foo.java @@ -0,0 +1,11 @@ +class A { + + class B { + + void m() { + hashCode(); + } + + } + +} \ No newline at end of file diff --git a/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution/initialIndex.txt b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution/initialIndex.txt new file mode 100644 index 000000000000..a833d7119d50 --- /dev/null +++ b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution/initialIndex.txt @@ -0,0 +1,15 @@ +Backward Hierarchy: +java.lang.Object -> A A$B + +Backward References: +A in Foo occurrences = 1 +A$B in Foo occurrences = 1 +A$B.(0) in Foo occurrences = 1 +A$B.hashCode(0) in Foo occurrences = 1 +A$B.m(0) in Foo occurrences = 1 +A.(0) in Foo occurrences = 1 +java.lang.Object.(0) in Foo occurrences = 2 + +Class Definitions: +A in Foo +A$B in Foo \ No newline at end of file diff --git a/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution2/Foo.java b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution2/Foo.java new file mode 100644 index 000000000000..ae9606bebd11 --- /dev/null +++ b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution2/Foo.java @@ -0,0 +1,14 @@ +class A { + + class B { + + + void m() { + xxxx(); + } + + } + + void xxxx() {} + +} \ No newline at end of file diff --git a/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution2/initialIndex.txt b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution2/initialIndex.txt new file mode 100644 index 000000000000..c9226dc75805 --- /dev/null +++ b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution2/initialIndex.txt @@ -0,0 +1,15 @@ +Backward Hierarchy: +java.lang.Object -> A A$B + +Backward References: +A in Foo occurrences = 1 +A$B in Foo occurrences = 1 +A$B.(0) in Foo occurrences = 1 +A$B.m(0) in Foo occurrences = 1 +A.(0) in Foo occurrences = 1 +A.xxxx(0) in Foo occurrences = 2 +java.lang.Object.(0) in Foo occurrences = 2 + +Class Definitions: +A in Foo +A$B in Foo \ No newline at end of file diff --git a/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution3/Foo.java b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution3/Foo.java new file mode 100644 index 000000000000..eb8ce21f8cb5 --- /dev/null +++ b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution3/Foo.java @@ -0,0 +1,11 @@ +class A { + + void mmmm() { + new Runnable() { + public void run() { + mmmm(); + } + }; + } + +} \ No newline at end of file diff --git a/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution3/initialIndex.txt b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution3/initialIndex.txt new file mode 100644 index 000000000000..7ee942bd73cd --- /dev/null +++ b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution3/initialIndex.txt @@ -0,0 +1,16 @@ +Backward Hierarchy: +java.lang.Object -> A anonymous(id=0) +java.lang.Runnable -> anonymous(id=0) + +Backward References: +A in Foo occurrences = 1 +A.(0) in Foo occurrences = 1 +A.mmmm(0) in Foo occurrences = 2 +java.lang.Object.(0) in Foo occurrences = 2 +java.lang.Runnable in Foo occurrences = 2 +java.lang.Runnable.(0) in Foo occurrences = 1 +java.lang.Runnable.run(0) in Foo occurrences = 1 + +Class Definitions: +A in Foo +anonymous(id=0) in Foo \ No newline at end of file diff --git a/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution4/Foo.java b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution4/Foo.java new file mode 100644 index 000000000000..59b16855ac5d --- /dev/null +++ b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution4/Foo.java @@ -0,0 +1,15 @@ +class A { + + void m() { + + new Runnable() { + public void run() { + if (false) { + run(); + } + } + }; + + } + +} \ No newline at end of file diff --git a/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution4/initialIndex.txt b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution4/initialIndex.txt new file mode 100644 index 000000000000..b70ea2adc93d --- /dev/null +++ b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution4/initialIndex.txt @@ -0,0 +1,16 @@ +Backward Hierarchy: +java.lang.Object -> A anonymous(id=0) +java.lang.Runnable -> anonymous(id=0) + +Backward References: +A in Foo occurrences = 1 +A.(0) in Foo occurrences = 1 +A.m(0) in Foo occurrences = 1 +java.lang.Object.(0) in Foo occurrences = 2 +java.lang.Runnable in Foo occurrences = 2 +java.lang.Runnable.(0) in Foo occurrences = 1 +java.lang.Runnable.run(0) in Foo occurrences = 2 + +Class Definitions: +A in Foo +anonymous(id=0) in Foo \ No newline at end of file diff --git a/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution5/Foo.java b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution5/Foo.java new file mode 100644 index 000000000000..4b4a02d0e3d2 --- /dev/null +++ b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution5/Foo.java @@ -0,0 +1,15 @@ +class A { + void m() { + new Runnable() { + public void run() { + if (false) { + xxx(); + } + } + }; + } + + private void xxx() { + + } +} \ No newline at end of file diff --git a/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution5/initialIndex.txt b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution5/initialIndex.txt new file mode 100644 index 000000000000..3b02de47dbfa --- /dev/null +++ b/jps/jps-builders/testData/referencesIndex/unqualifiedMethodCallResolution5/initialIndex.txt @@ -0,0 +1,16 @@ +Backward Hierarchy: +java.lang.Object -> A anonymous(id=0) +java.lang.Runnable -> anonymous(id=0) + +Backward References: +A in Foo occurrences = 1 +A.(0) in Foo occurrences = 1 +A.m(0) in Foo occurrences = 1 +java.lang.Object.(0) in Foo occurrences = 2 +java.lang.Runnable in Foo occurrences = 2 +java.lang.Runnable.(0) in Foo occurrences = 1 +java.lang.Runnable.run(0) in Foo occurrences = 1 + +Class Definitions: +A in Foo +anonymous(id=0) in Foo \ No newline at end of file diff --git a/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTest.kt b/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTest.kt index 1cd31656f501..c23cb0f5e152 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTest.kt +++ b/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTest.kt @@ -130,6 +130,7 @@ class ReferenceIndexTest : ReferenceIndexTestBase() { } fun testOccurrences() { + assertIndexOnRebuild("Foo.java", "Bar.java") } @@ -140,5 +141,29 @@ class ReferenceIndexTest : ReferenceIndexTestBase() { fun testAnnotation() { assertIndexOnRebuild("Foo.java") } + + fun testUnqualifiedMethodCallResolution() { + assertIndexOnRebuild("Foo.java") + } + + fun testUnqualifiedMethodCallResolution2() { + assertIndexOnRebuild("Foo.java") + } + + fun testUnqualifiedMethodCallResolution3() { + assertIndexOnRebuild("Foo.java") + } + + fun testUnqualifiedMethodCallResolution4() { + assertIndexOnRebuild("Foo.java") + } + + fun testUnqualifiedMethodCallResolution5() { + assertIndexOnRebuild("Foo.java") + } + + fun testQualifierResolution() { + assertIndexOnRebuild("Foo.java") + } } diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleIndex.java b/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleIndex.java index 9a401a674b46..aaa3f4f72e3b 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleIndex.java +++ b/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,17 +20,11 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.module.JpsModule; import java.io.File; -import java.util.Set; public abstract class JavaModuleIndex { /** * Returns a path to a module descriptor (module-info.java file) for the given module, * or {@code null} when there is no descriptor. */ - public abstract @Nullable File getModuleInfoFile(@NotNull JpsModule module); - - /** - * Returns {@code true} when at least one module in the chunk has a module descriptor (module-info.java file). - */ - public abstract boolean hasJavaModules(@NotNull Set chunk); + public abstract @Nullable File getModuleInfoFile(@NotNull JpsModule module, boolean forTests); } \ No newline at end of file diff --git a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexImpl.java index fe7eced0bfae..3a8e1704b8f0 100644 --- a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexImpl.java +++ b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -21,6 +21,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.java.JavaModuleIndex; +import org.jetbrains.jps.model.java.JavaSourceRootType; import org.jetbrains.jps.model.java.compiler.JpsCompilerExcludes; import org.jetbrains.jps.model.module.JpsModule; import org.jetbrains.jps.model.module.JpsModuleSourceRoot; @@ -30,9 +31,11 @@ import java.io.*; import java.util.Collections; import java.util.Map; import java.util.Properties; -import java.util.Set; public class JavaModuleIndexImpl extends JavaModuleIndex { + public static final String SOURCE_SUFFIX = ":S"; + public static final String TEST_SUFFIX = ":T"; + private static final String INDEX_PATH = "jigsaw/module-info.map"; private static final String NULL_PATH = "-"; private static final String MODULE_INFO_FILE = "module-info.java"; @@ -50,34 +53,27 @@ public class JavaModuleIndexImpl extends JavaModuleIndex { myExcludes = null; } + @Nullable @Override - public @Nullable File getModuleInfoFile(@NotNull JpsModule module) { - String key = module.getName(); + public File getModuleInfoFile(@NotNull JpsModule module, boolean forTests) { + String key = module.getName() + (forTests ? TEST_SUFFIX : SOURCE_SUFFIX); + if (myExcludes == null || myMapping.containsKey(key)) { return myMapping.get(key); } - File file = findModuleInfoFile(module); + File file = findModuleInfoFile(module, forTests ? JavaSourceRootType.TEST_SOURCE : JavaSourceRootType.SOURCE); myMapping.put(key, file); return file; } - @Override - public boolean hasJavaModules(@NotNull Set chunk) { - for (JpsModule module : chunk) { - if (getModuleInfoFile(module) != null) { - return true; - } - } - - return false; - } - - private File findModuleInfoFile(JpsModule module) { + private File findModuleInfoFile(JpsModule module, JavaSourceRootType rootType) { for (JpsModuleSourceRoot root : module.getSourceRoots()) { - File file = new File(JpsPathUtil.urlToOsPath(root.getUrl()), MODULE_INFO_FILE); - if (file.isFile() && !myExcludes.isExcluded(file)) { - return file; + if (rootType.equals(root.getRootType())) { + File file = new File(JpsPathUtil.urlToOsPath(root.getUrl()), MODULE_INFO_FILE); + if (file.isFile() && !myExcludes.isExcluded(file)) { + return file; + } } } @@ -94,13 +90,9 @@ public class JavaModuleIndexImpl extends JavaModuleIndex { File index = new File(storageRoot, INDEX_PATH); FileUtil.createParentDirs(index); - Writer writer = new OutputStreamWriter(new FileOutputStream(index), CharsetToolkit.UTF8_CHARSET); - try { + try (Writer writer = new OutputStreamWriter(new FileOutputStream(index), CharsetToolkit.UTF8_CHARSET)) { p.store(writer, null); } - finally { - writer.close(); - } } public static JavaModuleIndex load(@NotNull File storageRoot, @NotNull JpsCompilerExcludes excludes) { @@ -110,14 +102,8 @@ public class JavaModuleIndexImpl extends JavaModuleIndex { } Properties p = new Properties(); - try { - Reader reader = new InputStreamReader(new FileInputStream(index), CharsetToolkit.UTF8_CHARSET); - try { - p.load(reader); - } - finally { - reader.close(); - } + try (Reader reader = new InputStreamReader(new FileInputStream(index), CharsetToolkit.UTF8_CHARSET)) { + p.load(reader); } catch (IOException e) { throw new RuntimeException("Failed to read module index file: " + index, e); diff --git a/lib/xml-apis-ext.jar b/lib/xml-apis-ext.jar deleted file mode 100644 index a7869d68aacd..000000000000 Binary files a/lib/xml-apis-ext.jar and /dev/null differ diff --git a/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfileEntry.java b/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfileEntry.java index d2d041879c76..576402bc645c 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfileEntry.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfileEntry.java @@ -49,10 +49,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; +import java.util.*; /** * @author anna @@ -177,26 +174,32 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool { @NotNull public static Set getSuppressors(@NotNull PsiElement element) { FileViewProvider viewProvider = element.getContainingFile().getViewProvider(); - final InspectionSuppressor elementLanguageSuppressor = LanguageInspectionSuppressors.INSTANCE.forLanguage(element.getLanguage()); + final List elementLanguageSuppressor = LanguageInspectionSuppressors.INSTANCE.allForLanguage(element.getLanguage()); if (viewProvider instanceof TemplateLanguageFileViewProvider) { Set suppressors = new LinkedHashSet<>(); - ContainerUtil.addIfNotNull(suppressors, LanguageInspectionSuppressors.INSTANCE.forLanguage(viewProvider.getBaseLanguage())); + ContainerUtil.addAllNotNull(suppressors, LanguageInspectionSuppressors.INSTANCE.allForLanguage(viewProvider.getBaseLanguage())); for (Language language : viewProvider.getLanguages()) { - ContainerUtil.addIfNotNull(suppressors, LanguageInspectionSuppressors.INSTANCE.forLanguage(language)); + ContainerUtil.addAllNotNull(suppressors, LanguageInspectionSuppressors.INSTANCE.allForLanguage(language)); } - ContainerUtil.addIfNotNull(suppressors, elementLanguageSuppressor); + ContainerUtil.addAllNotNull(suppressors, elementLanguageSuppressor); return suppressors; } if (!element.getLanguage().isKindOf(viewProvider.getBaseLanguage())) { // handling embedding elements {@link EmbeddingElementType Set suppressors = new LinkedHashSet<>(); - ContainerUtil.addIfNotNull(suppressors, LanguageInspectionSuppressors.INSTANCE.forLanguage(viewProvider.getBaseLanguage())); - ContainerUtil.addIfNotNull(suppressors, elementLanguageSuppressor); + ContainerUtil.addAllNotNull(suppressors, LanguageInspectionSuppressors.INSTANCE.allForLanguage(viewProvider.getBaseLanguage())); + ContainerUtil.addAllNotNull(suppressors, elementLanguageSuppressor); return suppressors; } - return elementLanguageSuppressor != null - ? Collections.singleton(elementLanguageSuppressor) - : Collections.emptySet(); + int size = elementLanguageSuppressor.size(); + switch (size) { + case 0: + return Collections.emptySet(); + case 1: + return Collections.singleton(elementLanguageSuppressor.get(0)); + default: + return new java.util.HashSet<>(elementLanguageSuppressor); + } } public void cleanup(@NotNull Project project) { diff --git a/platform/analysis-api/src/com/intellij/codeInspection/reference/UnusedDeclarationFixProvider.java b/platform/analysis-api/src/com/intellij/codeInspection/reference/UnusedDeclarationFixProvider.java index 2b19e8fea234..94317a4ae9e6 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/reference/UnusedDeclarationFixProvider.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/reference/UnusedDeclarationFixProvider.java @@ -26,6 +26,7 @@ import org.jetbrains.annotations.NotNull; * @author Dmitry Avdeev * Date: 1/19/12 */ +@FunctionalInterface public interface UnusedDeclarationFixProvider { ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.unusedDeclarationFixProvider"); diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java b/platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java index 8c6a51472124..ef8d32691a16 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java @@ -284,7 +284,7 @@ public class InspectionEngine { } else if (language instanceof MetaLanguage) { Collection matchingLanguages = ((MetaLanguage) language).getMatchingLanguages(); - result = new HashSet<>(); + result = new THashSet<>(); for (Language matchingLanguage : matchingLanguages) { result.addAll(getLanguageWithDialects(wrapper, matchingLanguage)); } @@ -297,9 +297,9 @@ public class InspectionEngine { @NotNull private static Set getLanguageWithDialects(@NotNull LocalInspectionToolWrapper wrapper, Language language) { - Set result;List dialects = language.getDialects(); + List dialects = language.getDialects(); boolean applyToDialects = wrapper.applyToDialects(); - result = applyToDialects && !dialects.isEmpty() ? new THashSet<>(1 + dialects.size()) : new SmartHashSet<>(); + Set result = applyToDialects && !dialects.isEmpty() ? new THashSet<>(1 + dialects.size()) : new SmartHashSet<>(); result.add(language.getID()); if (applyToDialects) { for (Language dialect : dialects) { diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefElementImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefElementImpl.java index 9e98ba44659c..d6016c98535c 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefElementImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefElementImpl.java @@ -56,7 +56,7 @@ public abstract class RefElementImpl extends RefEntityImpl implements RefElement private List myOutReferences; private List myInReferences; - private String[] mySuppressions = null; + private String[] mySuppressions; private boolean myIsDeleted ; protected static final int IS_REACHABLE_MASK = 0x40; diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefFileImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefFileImpl.java index bae2663b0dcd..ec6d127dc99a 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefFileImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefFileImpl.java @@ -64,7 +64,7 @@ public class RefFileImpl extends RefElementImpl implements RefFile { } @Nullable - public static RefElement fileFromExternalName(final RefManager manager, final String fqName) { + static RefElement fileFromExternalName(final RefManager manager, final String fqName) { final VirtualFile virtualFile = VirtualFileManager.getInstance().findFileByUrl(PathMacroManager.getInstance(manager.getProject()).expandPath(fqName)); if (virtualFile != null) { final PsiFile psiFile = PsiManager.getInstance(manager.getProject()).findFile(virtualFile); diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java index 81dcd162ea0f..40c81d2f7f44 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java @@ -77,11 +77,10 @@ public class RefManagerImpl extends RefManager { private AnalysisScope myScope; private RefProject myRefProject; - private final Map myRefTable = new THashMap<>(); // guarded by myRefTableLock - private final Map myPsiToRefTable = new THashMap<>(); // replacement of myRefTable, guarded by myRefTableLock - private final Object myRefTableLock = new Object(); - - private List mySortedRefs; // guarded by myRefTable + private final ConcurrentMap myRefTable = ContainerUtil.newConcurrentMap(); + private final ConcurrentMap myPsiToRefTable = ContainerUtil.newConcurrentMap(); // replacement of myRefTable + + private volatile List mySortedRefs; private final ConcurrentMap myModules = ContainerUtil.newConcurrentMap(); private final ProjectIterator myProjectIterator = new ProjectIterator(); @@ -118,7 +117,7 @@ public class RefManagerImpl extends RefManager { } } - public String internName(@NotNull String name) { + String internName(@NotNull String name) { synchronized (myNameInterner) { return myNameInterner.intern(name); } @@ -147,10 +146,8 @@ public class RefManagerImpl extends RefManager { public void cleanup() { myScope = null; myRefProject = null; - synchronized (myRefTableLock) { - (usePsiAsKey() ? myPsiToRefTable : myRefTable).clear(); - mySortedRefs = null; - } + (usePsiAsKey() ? myPsiToRefTable : myRefTable).clear(); + mySortedRefs = null; myModules.clear(); myContext = null; @@ -167,31 +164,31 @@ public class RefManagerImpl extends RefManager { } - public void fireNodeInitialized(RefElement refElement) { + private void fireNodeInitialized(RefElement refElement) { for (RefGraphAnnotator annotator : myGraphAnnotators) { annotator.onInitialize(refElement); } } - public void fireNodeMarkedReferenced(RefElement refWhat, - RefElement refFrom, - boolean referencedFromClassInitializer, - final boolean forReading, - final boolean forWriting) { + void fireNodeMarkedReferenced(RefElement refWhat, + RefElement refFrom, + boolean referencedFromClassInitializer, + final boolean forReading, + final boolean forWriting) { for (RefGraphAnnotator annotator : myGraphAnnotators) { annotator.onMarkReferenced(refWhat, refFrom, referencedFromClassInitializer, forReading, forWriting); } } - public void fireNodeMarkedReferenced(PsiElement what, - PsiElement from, - boolean referencedFromClassInitializer) { + void fireNodeMarkedReferenced(PsiElement what, + PsiElement from, + boolean referencedFromClassInitializer) { for (RefGraphAnnotator annotator : myGraphAnnotators) { annotator.onMarkReferenced(what, from, referencedFromClassInitializer); } } - public void fireBuildReferences(RefElement refElement) { + void fireBuildReferences(RefElement refElement) { for (RefGraphAnnotator annotator : myGraphAnnotators) { annotator.onReferencesBuild(refElement); } @@ -311,11 +308,11 @@ public class RefManagerImpl extends RefManager { if (groupName != null) return groupName; } - final LinkedList containingDirs = new LinkedList<>(); RefEntity parent = entity.getOwner(); while (parent != null && !(parent instanceof RefDirectory)) { parent = parent.getOwner(); } + final LinkedList containingDirs = new LinkedList<>(); while (parent instanceof RefDirectory) { containingDirs.addFirst(parent.getName()); parent = parent.getOwner(); @@ -356,16 +353,14 @@ public class RefManagerImpl extends RefManager { myIsInProcess = false; if (myScope != null) myScope.invalidate(); - synchronized (myRefTableLock) { - mySortedRefs = null; - } + mySortedRefs = null; } public void startOfflineView() { myOfflineView = true; } - public boolean isOfflineView() { + boolean isOfflineView() { return myOfflineView; } @@ -386,21 +381,19 @@ public class RefManagerImpl extends RefManager { } @NotNull - public List getSortedElements() { - List answer; - synchronized (myRefTableLock) { - if (mySortedRefs != null) return mySortedRefs; + List getSortedElements() { + List answer = mySortedRefs; + if (answer != null) return answer; - answer = new ArrayList<>(usePsiAsKey() ? myPsiToRefTable.values() : myRefTable.values()); - } - ReadAction.run(() -> ContainerUtil.quickSort(answer, (o1, o2) -> { + answer = new ArrayList<>(usePsiAsKey() ? myPsiToRefTable.values() : myRefTable.values()); + List list = answer; + ReadAction.run(() -> ContainerUtil.quickSort(list, (o1, o2) -> { VirtualFile v1 = ((RefElementImpl)o1).getVirtualFile(); VirtualFile v2 = ((RefElementImpl)o2).getVirtualFile(); return (v1 != null ? v1.hashCode() : 0) - (v2 != null ? v2.hashCode() : 0); })); - synchronized (myRefTableLock) { - return mySortedRefs = Collections.unmodifiableList(answer); - } + mySortedRefs = answer = Collections.unmodifiableList(answer); + return answer; } @NotNull @@ -416,43 +409,37 @@ public class RefManagerImpl extends RefManager { extension.removeReference(refElem); } - synchronized (myRefTableLock) { - mySortedRefs = null; - if (element != null && - (usePsiAsKey() ? myPsiToRefTable.remove(element) : myRefTable.remove(createAnchor(element))) != null) return; + if (element != null && + (usePsiAsKey() ? myPsiToRefTable.remove(element) : myRefTable.remove(createAnchor(element))) != null) return; - //PsiElement may have been invalidated and new one returned by getElement() is different so we need to do this stuff. - if (usePsiAsKey()) { - for (Map.Entry entry : myPsiToRefTable.entrySet()) { - RefElement value = entry.getValue(); - PsiElement anchor = entry.getKey(); - if (value == refElem) { - myPsiToRefTable.remove(anchor); - break; - } - } - } else { - for (Map.Entry entry : myRefTable.entrySet()) { - RefElement value = entry.getValue(); - PsiAnchor anchor = entry.getKey(); - if (value == refElem) { - myRefTable.remove(anchor); - break; - } + //PsiElement may have been invalidated and new one returned by getElement() is different so we need to do this stuff. + if (usePsiAsKey()) { + for (Map.Entry entry : myPsiToRefTable.entrySet()) { + RefElement value = entry.getValue(); + PsiElement anchor = entry.getKey(); + if (value == refElem) { + myPsiToRefTable.remove(anchor); + break; } } } + else { + for (Map.Entry entry : myRefTable.entrySet()) { + RefElement value = entry.getValue(); + PsiAnchor anchor = entry.getKey(); + if (value == refElem) { + myRefTable.remove(anchor); + break; + } + } + } + mySortedRefs = null; } @NotNull private static PsiAnchor createAnchor(@NotNull final PsiElement element) { return ApplicationManager.getApplication().runReadAction( - new Computable() { - @Override - public PsiAnchor compute() { - return PsiAnchor.create(element); - } - } + (Computable)() -> PsiAnchor.create(element) ); } @@ -501,13 +488,8 @@ public class RefManagerImpl extends RefManager { @Nullable public RefElement getReference(final PsiElement elem, final boolean ignoreScope) { - if (ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - return elem == null || !elem.isValid() || - elem instanceof LightElement || !(elem instanceof PsiDirectory) && !belongsToScope(elem, ignoreScope); - } - })) { + if (ApplicationManager.getApplication().runReadAction((Computable)() -> elem == null || !elem.isValid() || + elem instanceof LightElement || !(elem instanceof PsiDirectory) && !belongsToScope(elem, ignoreScope))) { return null; } @@ -572,41 +554,37 @@ public class RefManagerImpl extends RefManager { } @Nullable - protected T getFromRefTableOrCache(final PsiElement element, @NotNull NullableFactory factory) { + T getFromRefTableOrCache(final PsiElement element, @NotNull NullableFactory factory) { return getFromRefTableOrCache(element, factory, null); } @Nullable - private T getFromRefTableOrCache(final PsiElement element, + private T getFromRefTableOrCache(@NotNull PsiElement element, @NotNull NullableFactory factory, @Nullable Consumer whenCached) { PsiAnchor psiAnchor = createAnchor(element); - T result; - synchronized (myRefTableLock) { + //noinspection unchecked + T result = (T)(usePsiAsKey() ? myPsiToRefTable.get(element) : myRefTable.get(psiAnchor)); + + if (result != null) return result; + + if (!isValidPointForReference()) { + //LOG.assertTrue(true, "References may become invalid after process is finished"); + return null; + } + + result = factory.create(); + if (result == null) return null; + + mySortedRefs = null; + RefElement prev = usePsiAsKey() ? myPsiToRefTable.putIfAbsent(element, result) : myRefTable.putIfAbsent(psiAnchor, result); + if (prev != null) { //noinspection unchecked - result = (T) (usePsiAsKey() ? myPsiToRefTable.get(element) : myRefTable.get(psiAnchor)); - - if (result != null) return result; - - if (!isValidPointForReference()) { - //LOG.assertTrue(true, "References may become invalid after process is finished"); - return null; - } - - result = factory.create(); - if (result == null) return null; - - if (usePsiAsKey()) { - myPsiToRefTable.put(element, result); - } else { - myRefTable.put(psiAnchor, result); - } - mySortedRefs = null; - - if (whenCached != null) { - whenCached.consume(result); - } + result = (T)prev; + } + else if (whenCached != null) { + whenCached.consume(result); } return result; @@ -632,24 +610,15 @@ public class RefManagerImpl extends RefManager { private boolean belongsToScope(final PsiElement psiElement, final boolean ignoreScope) { if (psiElement == null || !psiElement.isValid()) return false; if (psiElement instanceof PsiCompiledElement) return false; - final PsiFile containingFile = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiFile compute() { - return psiElement.getContainingFile(); - } - }); + final PsiFile containingFile = ApplicationManager.getApplication().runReadAction((Computable)psiElement::getContainingFile); if (containingFile == null) { return false; } for (RefManagerExtension extension : myExtensions.values()) { if (!extension.belongsToScope(psiElement)) return false; } - final Boolean inProject = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - return psiElement.getManager().isInProject(psiElement); - } - }); + final Boolean inProject = ApplicationManager.getApplication().runReadAction( + (Computable)() -> psiElement.getManager().isInProject(psiElement)); return inProject.booleanValue() && (ignoreScope || getScope() == null || getScope().contains(psiElement)); } @@ -675,7 +644,7 @@ public class RefManagerImpl extends RefManager { if (!deletedRefs.contains(refElement)) deletedRefs.add(refElement); } - protected boolean isValidPointForReference() { + boolean isValidPointForReference() { return myIsInProcess || myOfflineView || ApplicationManager.getApplication().isUnitTestMode(); } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefProjectImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefProjectImpl.java index 57dab12475c0..7fda523e25ef 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefProjectImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefProjectImpl.java @@ -30,7 +30,7 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; public class RefProjectImpl extends RefEntityImpl implements RefProject { - public RefProjectImpl(@NotNull RefManager refManager) { + RefProjectImpl(@NotNull RefManager refManager) { super(refManager.getProject().getName(), refManager); } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/SmartRefElementPointerImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/SmartRefElementPointerImpl.java index 8e145ec4d7c7..29dd39ce8404 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/SmartRefElementPointerImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/SmartRefElementPointerImpl.java @@ -58,13 +58,6 @@ public class SmartRefElementPointerImpl implements SmartRefElementPointer { myType = type; } - public SmartRefElementPointerImpl(final String type, final String fqName, final RefManager manager) { - myIsPersistent = false; - myFQName = fqName; - myType = type; - resolve(manager); - } - @Override public boolean isPersistent() { return myIsPersistent; @@ -91,8 +84,7 @@ public class SmartRefElementPointerImpl implements SmartRefElementPointer { @Override public boolean resolve(@NotNull RefManager manager) { if (myRefElement != null) { - if (myRefElement instanceof RefElement && myRefElement.isValid()) return true; - return false; + return myRefElement instanceof RefElement && myRefElement.isValid(); } myRefElement = manager.getReference(myType, getFQName()); return myRefElement != null; diff --git a/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java b/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java index fd6e9344201d..98cc641c3b6c 100644 --- a/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java +++ b/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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 com.intellij.psi.search.PsiFileSystemItemProcessor; import com.intellij.refactoring.rename.BindablePsiReference; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -156,9 +157,18 @@ public class FileReference implements PsiFileReference, FileReferenceOwner, PsiP final Collection result, final boolean caseSensitive) { if (isAllowedEmptyPath(text) || ".".equals(text) || "/".equals(text)) { + if (context instanceof FileReferenceResolver) { + ContainerUtil.addIfNotNull(result, resolveFileReferenceResolver((FileReferenceResolver)context, text)); + return; + } result.add(new PsiElementResolveResult(context)); } else if ("..".equals(text)) { + if (context instanceof FileReferenceResolver) { + ContainerUtil.addIfNotNull(result, resolveFileReferenceResolver((FileReferenceResolver)context, text)); + return; + } + final PsiFileSystemItem resolved = context.getParent(); if (resolved != null) { result.add(new PsiElementResolveResult(resolved)); @@ -189,9 +199,9 @@ public class FileReference implements PsiFileReference, FileReferenceOwner, PsiP context = ((PackagePrefixFileSystemItem)context).getDirectory(); } else if (context instanceof FileReferenceResolver) { - PsiFileSystemItem child = ((FileReferenceResolver)context).resolveFileReference(this, decoded); + ResolveResult child = resolveFileReferenceResolver((FileReferenceResolver)context, decoded); if (child != null) { - result.add(new PsiElementResolveResult(getOriginalFile(child))); + result.add(child); return; } } @@ -241,6 +251,12 @@ public class FileReference implements PsiFileReference, FileReferenceOwner, PsiP return null; } + @Nullable + private ResolveResult resolveFileReferenceResolver(@NotNull FileReferenceResolver fileReferenceResolver, @NotNull String text) { + PsiFileSystemItem resolve = fileReferenceResolver.resolveFileReference(this, text); + return resolve != null ? new PsiElementResolveResult(getOriginalFile(resolve)) : null; + } + private static boolean caseSensitivityApplies(PsiDirectory context, boolean caseSensitive) { VirtualFileSystem fs = context.getVirtualFile().getFileSystem(); return fs.isCaseSensitive() == caseSensitive; diff --git a/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java b/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java index a4100b567f25..b1b831196e50 100644 --- a/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java +++ b/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -367,15 +367,23 @@ public class FileReferenceSet { final FileReferenceHelper[] helpers = FileReferenceHelperRegistrar.getHelpers(); final ArrayList list = new ArrayList<>(); final Project project = file.getProject(); + boolean hasRealContexts = false; for (FileReferenceHelper helper : helpers) { if (helper.isMine(project, virtualFile)) { if (!list.isEmpty() && helper.isFallback()) { continue; } - list.addAll(helper.getContexts(project, virtualFile)); + Collection contexts = helper.getContexts(project, virtualFile); + for (PsiFileSystemItem context : contexts) { + list.add(context); + hasRealContexts |= !(context instanceof FileReferenceResolver); + } } } if (!list.isEmpty()) { + if (!hasRealContexts) { + list.addAll(getParentDirectoryContext()); + } return list; } return getParentDirectoryContext(); diff --git a/platform/boot/src/com/intellij/lang/properties/charset/Native2AsciiCharset.java b/platform/boot/src/com/intellij/lang/properties/charset/Native2AsciiCharset.java index 21e0c953ee0a..abf4ef8c7568 100644 --- a/platform/boot/src/com/intellij/lang/properties/charset/Native2AsciiCharset.java +++ b/platform/boot/src/com/intellij/lang/properties/charset/Native2AsciiCharset.java @@ -25,16 +25,17 @@ import java.util.concurrent.ConcurrentMap; */ public class Native2AsciiCharset extends Charset { + @SuppressWarnings("SSBasedInspection") private static final String[] ALIASES = new String[0]; private final Charset myBaseCharset; - @SuppressWarnings({"HardCodedStringLiteral"}) private static final String NAME_PREFIX = "NATIVE_TO_ASCII_"; - @SuppressWarnings({"HardCodedStringLiteral"}) private static final String DEFAULT_ENCODING_NAME = "ISO-8859-1"; + private static final String NAME_PREFIX = "NATIVE_TO_ASCII_"; + private static final String DEFAULT_ENCODING_NAME = "ISO-8859-1"; private Native2AsciiCharset(String canonicalName) { super(canonicalName, ALIASES); - String baseCharsetName = canonicalName.substring(NAME_PREFIX.length()); Charset baseCharset = null; try { + String baseCharsetName = canonicalName.substring(NAME_PREFIX.length()); baseCharset = Charset.forName(baseCharsetName); } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { @@ -63,7 +64,7 @@ public class Native2AsciiCharset extends Charset { return new Native2AsciiCharsetEncoder(this); } - public Charset getBaseCharset() { + Charset getBaseCharset() { return myBaseCharset; } public static String makeNative2AsciiEncodingName(String baseCharsetName) { diff --git a/platform/boot/src/com/intellij/lang/properties/charset/Native2AsciiCharsetDecoder.java b/platform/boot/src/com/intellij/lang/properties/charset/Native2AsciiCharsetDecoder.java index 7da4b9cdf6b7..c20678e96553 100644 --- a/platform/boot/src/com/intellij/lang/properties/charset/Native2AsciiCharsetDecoder.java +++ b/platform/boot/src/com/intellij/lang/properties/charset/Native2AsciiCharsetDecoder.java @@ -105,7 +105,7 @@ class Native2AsciiCharsetDecoder extends CharsetDecoder { if (end <= start) return; ByteBuffer byteBuffer = ByteBuffer.wrap(buf, start, end-start); CharBuffer charBuffer = myBaseCharset.decode(byteBuffer); - myOutBuffer.append(charBuffer.toString()); + myOutBuffer.append(charBuffer); } private static char unicode(byte[] ord) { diff --git a/platform/boot/src/com/intellij/lang/properties/charset/Native2AsciiCharsetEncoder.java b/platform/boot/src/com/intellij/lang/properties/charset/Native2AsciiCharsetEncoder.java index c07e69d0b324..b122df753614 100644 --- a/platform/boot/src/com/intellij/lang/properties/charset/Native2AsciiCharsetEncoder.java +++ b/platform/boot/src/com/intellij/lang/properties/charset/Native2AsciiCharsetEncoder.java @@ -36,6 +36,7 @@ class Native2AsciiCharsetEncoder extends CharsetEncoder { myBaseCharset = charset.getBaseCharset(); } + @Override protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { while (in.position() < in.limit()) { in.mark(); diff --git a/platform/bootstrap/src/com/intellij/ide/WindowsCommandLineProcessor.java b/platform/bootstrap/src/com/intellij/ide/WindowsCommandLineProcessor.java index 176ada211633..445aa4ee5b74 100644 --- a/platform/bootstrap/src/com/intellij/ide/WindowsCommandLineProcessor.java +++ b/platform/bootstrap/src/com/intellij/ide/WindowsCommandLineProcessor.java @@ -24,16 +24,16 @@ import java.lang.reflect.Method; * * @author yole */ -@SuppressWarnings("UnusedDeclaration") public class WindowsCommandLineProcessor { // The WindowsCommandLineProcessor class which is loaded in the main IDEA (non-bootstrap) classloader. - public static Class ourMirrorClass = null; + public static Class ourMirrorClass; - public static WindowsCommandLineListener LISTENER = null; + public static WindowsCommandLineListener LISTENER; /** * NOTE: This method is called through JNI by the Windows launcher. Please do not delete or rename it. */ + @SuppressWarnings("unused") public static void processWindowsLauncherCommandLine(final String currentDirectory, final String commandLine) { if (ourMirrorClass != null) { try { diff --git a/platform/bootstrap/src/com/intellij/ide/startup/StartupActionScriptManager.java b/platform/bootstrap/src/com/intellij/ide/startup/StartupActionScriptManager.java index 5b1a45d23646..8d70a7e18153 100644 --- a/platform/bootstrap/src/com/intellij/ide/startup/StartupActionScriptManager.java +++ b/platform/bootstrap/src/com/intellij/ide/startup/StartupActionScriptManager.java @@ -31,7 +31,7 @@ import java.util.List; /** * @author cdr */ -@SuppressWarnings({"HardCodedStringLiteral"}) +@SuppressWarnings("HardCodedStringLiteral") public class StartupActionScriptManager { private static final Logger LOG = Logger.getInstance("#com.intellij.ide.startup.StartupActionScriptManager"); @NonNls public static final String STARTUP_WIZARD_MODE = "StartupWizardMode"; @@ -47,7 +47,7 @@ public class StartupActionScriptManager { for (ActionCommand actionCommand : commands) { actionCommand.execute(); } - if (commands.size() > 0) { + if (!commands.isEmpty()) { commands.clear(); saveActionScript(commands); @@ -141,6 +141,7 @@ public class StartupActionScriptManager { (myDestination == null ? "" : ", " + myDestination.getAbsolutePath()) + "]"; } + @Override public void execute() throws IOException { // create dirs for destination File parentFile = myDestination.getParentFile(); @@ -174,9 +175,9 @@ public class StartupActionScriptManager { public static class UnzipCommand implements Serializable, ActionCommand { @NonNls private static final String action = "unzip"; - private File mySource; - private FilenameFilter myFilenameFilter; - private File myDestination; + private final File mySource; + private final FilenameFilter myFilenameFilter; + private final File myDestination; public UnzipCommand(File source, File destination) { this(source, destination, null); @@ -193,6 +194,7 @@ public class StartupActionScriptManager { (myDestination == null ? "" : ", " + myDestination.getAbsolutePath()) + "]"; } + @Override public void execute() throws IOException { if (!mySource.exists()) { // Note, that we can not use LOG at this moment because it throws AssertionError @@ -234,6 +236,7 @@ public class StartupActionScriptManager { return action + "[" + mySource.getAbsolutePath() + "]"; } + @Override public void execute() throws IOException { if (mySource != null && mySource.exists() && !FileUtilRt.delete(mySource)) { //noinspection HardCodedStringLiteral,UseOfSystemOutOrSystemErr diff --git a/platform/bootstrap/src/com/intellij/idea/Main.java b/platform/bootstrap/src/com/intellij/idea/Main.java index 64cb14a30fe1..bcf0a2d7c7e7 100644 --- a/platform/bootstrap/src/com/intellij/idea/Main.java +++ b/platform/bootstrap/src/com/intellij/idea/Main.java @@ -115,7 +115,7 @@ public class Main { Comparing.strEqual(firstArg, "keymap") || Comparing.strEqual(firstArg, "inspections") || Comparing.strEqual(firstArg, "intentions") || - (firstArg.length() < 20 && firstArg.endsWith("inspect")); + firstArg.length() < 20 && firstArg.endsWith("inspect"); } private static boolean isCommandLine(String[] args) { @@ -136,7 +136,6 @@ public class Main { return args.length > 0 && Comparing.strEqual(args[0], "traverseUI"); } - @SuppressWarnings("ThrowableResultOfMethodCallIgnored") public static void showMessage(String title, Throwable t) { StringWriter message = new StringWriter(); diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/BuildPaths.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/BuildPaths.groovy index 0e23f8b8f0a2..ee941d67ce8d 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/BuildPaths.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/BuildPaths.groovy @@ -58,4 +58,9 @@ abstract class BuildPaths { * Path to a directory containing JDK (currently Java 8) which is used to compile the project */ String jdkHome + + /** + * Path to a directory containing Kotlin plugin with compiler which is used to compile the project + */ + String kotlinHome } diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CompilationContext.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CompilationContext.groovy index 9076ea2f5ae3..7a026781c3be 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CompilationContext.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CompilationContext.groovy @@ -26,6 +26,7 @@ import org.jetbrains.jps.model.module.JpsModule @CompileStatic interface CompilationContext { AntBuilder getAnt() + GradleRunner getGradle() BuildOptions getOptions() BuildMessages getMessages() BuildPaths getPaths() diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/GradleRunner.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/GradleRunner.groovy new file mode 100644 index 000000000000..616300cb9ba2 --- /dev/null +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/GradleRunner.groovy @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2017 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.intellij.build + +import com.intellij.openapi.util.SystemInfo +import groovy.transform.CompileStatic + +@CompileStatic +class GradleRunner { + private final File projectDir + private final BuildMessages messages + + GradleRunner(File projectDir, BuildMessages messages) { + this.messages = messages + this.projectDir = projectDir + } + + /** + * Invokes Gradle tasks on {@link #projectDir} project. + * Logs error and stops the build process if Gradle process is failed. + */ + def run(String title, String... tasks) { + runInner(title, false, tasks) + } + + /** + * Invokes Gradle tasks on {@link #projectDir} project. + * Ignores the result of running Gradle. + */ + def forceRun(String title, String... tasks) { + runInner(title, true, tasks) + } + + private def runInner(String title, boolean force, String... tasks) { + messages.block("Gradle $tasks") { + messages.progress(title) + if (!runInner(tasks)) { + def errorMessage = "Failed to complete `gradle ${tasks.join(' ')}`" + if (!force) { + messages.warning(errorMessage) + } + else { + messages.error(errorMessage) + } + } + } + } + + private def runInner(String... tasks) { + def gradleScript = SystemInfo.isWindows ? 'gradlew.bat' : 'gradlew' + List command = new ArrayList() + command.add("${projectDir.absolutePath}/$gradleScript".toString()) + command.addAll(tasks) + command.add('--stacktrace') + def process = new ProcessBuilder(command).directory(projectDir).start() + process.consumeProcessOutputStream((OutputStream)System.out) + process.consumeProcessErrorStream((OutputStream)System.err) + return process.waitFor() == 0 + } +} diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/TestingOptions.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/TestingOptions.groovy index d027251302d8..70301fdbc0c5 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/TestingOptions.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/TestingOptions.groovy @@ -28,7 +28,7 @@ class TestingOptions { *

Test groups are defined in testGroups.properties files and there is an implicit 'ALL_EXCLUDE_DEFINED' group for tests which aren't * included into any group and 'ALL' group for all tests. By default 'ALL_EXCLUDE_DEFINED' group is used.

*/ - String testGroup = System.getProperty("intellij.build.test.groups", OLD_TEST_GROUP) + String testGroups = System.getProperty("intellij.build.test.groups", OLD_TEST_GROUP) /** * Semicolon-separated patterns for test class names which need to be executed. Wildcard '*' is supported. diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BaseLayoutSpec.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BaseLayoutSpec.groovy index 76d5bf96cfb3..7c9016d55725 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BaseLayoutSpec.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BaseLayoutSpec.groovy @@ -31,7 +31,7 @@ class BaseLayoutSpec { * 'Runtime' to be copied to the 'lib' directory of the plugin. * * @param relativeJarPath target JAR path relative to 'lib' directory of the plugin; different modules may be packed into the same JAR, - * but don't use this for new plugins; this parameter is temporary added to keep layout of old plugins. + * but don't use this for new plugins; this parameter is temporary added to keep layout of old plugins. * @param localizableResourcesInCommonJar if {@code true} the translatable resources from the module (messages, inspection descriptions, etc) will be * placed into a separate 'resources_en.jar'. Do not use this for new plugins, this parameter is temporary added to keep layout of old plugins. */ diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy index 635c44e563e3..deaa91c45bd9 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy @@ -48,7 +48,6 @@ class BuildContextImpl extends BuildContext { def context = new BuildContextImpl(compilationContext, productProperties, windowsDistributionCustomizer, linuxDistributionCustomizer, macDistributionCustomizer, proprietaryBuildTools) - setupDependencies(context.messages, communityHome) return context } @@ -76,13 +75,6 @@ class BuildContextImpl extends BuildContext { bootClassPathJarNames = ["bootstrap.jar", "extensions.jar", "util.jar", "jdom.jar", "log4j.jar", "trove4j.jar", "jna.jar"] } - private static void setupDependencies(BuildMessages messages, String communityHome) { - messages.info("Setting up installer dependencies") - if (!BuildUtils.gradle(new File(communityHome, 'build/dependencies/'), 'setupDependencies')) { - messages.error("Cannot setup installer dependencies") - } - } - private String readSnapshotBuildNumber() { new File(paths.communityHome, "build.txt").text.trim() } @@ -118,6 +110,11 @@ class BuildContextImpl extends BuildContext { compilationContext.ant } + @Override + GradleRunner getGradle() { + compilationContext.gradle + } + @Override BuildOptions getOptions() { compilationContext.options diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildTasksImpl.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildTasksImpl.groovy index 612c0f7a8128..bf7d95395c35 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildTasksImpl.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildTasksImpl.groovy @@ -17,11 +17,7 @@ package org.jetbrains.intellij.build.impl import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.text.StringUtil -import org.jetbrains.intellij.build.BuildContext -import org.jetbrains.intellij.build.BuildOptions -import org.jetbrains.intellij.build.BuildTasks -import org.jetbrains.intellij.build.CompilationTasks -import org.jetbrains.intellij.build.ProductModulesLayout +import org.jetbrains.intellij.build.* import org.jetbrains.jps.model.java.JavaResourceRootType import org.jetbrains.jps.model.java.JavaSourceRootType import org.jetbrains.jps.model.module.JpsModule @@ -277,7 +273,7 @@ idea.fatal.error.notification=disabled if (buildContext.productProperties.scrambleMainJar) { scramble() } - + buildContext.gradle.run('Setting up JetBrains JREs', 'setupJbre') layoutShared() def propertiesFile = patchIdeaPropertiesFile() diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildUtils.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildUtils.groovy index fbd3309c0fd6..5bb4304a048e 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildUtils.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildUtils.groovy @@ -15,7 +15,6 @@ */ package org.jetbrains.intellij.build.impl -import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.text.StringUtil import groovy.transform.CompileStatic @@ -83,15 +82,4 @@ class BuildUtils { return System.out } } - - static boolean gradle(File projectDir, String... tasks) { - def gradleScript = SystemInfo.isWindows ? "gradlew.bat" : "gradlew" - List command = new ArrayList() - command.add("${projectDir.absolutePath}/$gradleScript".toString()) - command.addAll(tasks) - def process = new ProcessBuilder(command).directory(projectDir).start() - process.consumeProcessOutputStream((OutputStream)System.out) - process.consumeProcessErrorStream((OutputStream)System.err) - return process.waitFor() == 0 - } } \ No newline at end of file diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/CompilationContextImpl.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/CompilationContextImpl.groovy index 20f0ba0cd0a0..ba3b2755032f 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/CompilationContextImpl.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/CompilationContextImpl.groovy @@ -19,10 +19,7 @@ import com.intellij.openapi.util.io.FileUtil import groovy.transform.CompileDynamic import groovy.transform.CompileStatic import org.codehaus.gant.GantBinding -import org.jetbrains.intellij.build.BuildMessages -import org.jetbrains.intellij.build.BuildOptions -import org.jetbrains.intellij.build.BuildPaths -import org.jetbrains.intellij.build.CompilationContext +import org.jetbrains.intellij.build.* import org.jetbrains.jps.gant.JpsGantProjectBuilder import org.jetbrains.jps.gant.JpsGantTool import org.jetbrains.jps.model.JpsGlobal @@ -34,12 +31,14 @@ import org.jetbrains.jps.model.serialization.JpsProjectLoader import org.jetbrains.jps.util.JpsPathUtil import java.util.function.BiFunction + /** * @author nik */ @CompileStatic class CompilationContextImpl implements CompilationContext { final AntBuilder ant + final GradleRunner gradle final BuildOptions options final BuildMessages messages final BuildPaths paths @@ -66,51 +65,53 @@ class CompilationContextImpl implements CompilationContext { messages.error("communityHome ($communityHome) doesn't point to a directory containing IntelliJ Community sources") } + GradleRunner gradle = new GradleRunner(new File(communityHome, 'build/dependencies'), messages) + if (!options.isInDevelopmentMode) { + setupCompilationDependencies(gradle) + } + projectHome = toCanonicalPath(projectHome) def jdk8Home = toCanonicalPath(JdkUtils.computeJdkHome(messages, "jdk8Home", "$projectHome/build/jdk/1.8", "JDK_18_x64")) + def kotlinHome = toCanonicalPath("$communityHome/build/dependencies/build/kotlin/Kotlin") - setupDependencies(messages, communityHome) if (project.modules.isEmpty()) { - loadProject(communityHome, projectHome, jdk8Home, project, global, messages) + loadProject(projectHome, jdk8Home, kotlinHome, project, global, messages) } else { //todo[nik] currently we need this to build IDEA CE from IDEA UI build scripts. It would be better to create a separate JpsProject instance instead messages.info("Skipping loading project because it's already loaded") } - def context = new CompilationContextImpl(ant, projectBuilder, project, global, communityHome, projectHome, jdk8Home, messages, + def context = new CompilationContextImpl(ant, gradle, projectBuilder, project, global, communityHome, projectHome, jdk8Home, kotlinHome, messages, buildOutputRootEvaluator, options) context.prepareForBuild() return context } - private CompilationContextImpl(AntBuilder ant, JpsGantProjectBuilder projectBuilder, JpsProject project, JpsGlobal global, - String communityHome, String projectHome, String jdk8Home, BuildMessages messages, - BiFunction buildOutputRootEvaluator, BuildOptions options) { + private CompilationContextImpl(AntBuilder ant, GradleRunner gradle, JpsGantProjectBuilder projectBuilder, JpsProject project, + JpsGlobal global, String communityHome, String projectHome, String jdk8Home, String kotlinHome, + BuildMessages messages, BiFunction buildOutputRootEvaluator, + BuildOptions options) { this.ant = ant + this.gradle = gradle this.project = project this.global = global this.options = options this.projectBuilder = projectBuilder this.messages = messages String buildOutputRoot = options.outputRootPath ?: buildOutputRootEvaluator.apply(project, messages) - this.paths = new BuildPathsImpl(communityHome, projectHome, buildOutputRoot, jdk8Home) + this.paths = new BuildPathsImpl(communityHome, projectHome, buildOutputRoot, jdk8Home, kotlinHome) } CompilationContextImpl createCopy(AntBuilder ant, BuildMessages messages, BuildOptions options, BiFunction buildOutputRootEvaluator) { - return new CompilationContextImpl(ant, projectBuilder, project, global, paths.communityHome, paths.projectHome, paths.jdkHome, - messages, buildOutputRootEvaluator, options) + return new CompilationContextImpl(ant, gradle, projectBuilder, project, global, paths.communityHome, paths.projectHome, paths.jdkHome, + paths.kotlinHome, messages, buildOutputRootEvaluator, options) } - private static void loadProject(String communityHome, String projectHome, String jdkHome, JpsProject project, JpsGlobal global, + private static void loadProject(String projectHome, String jdkHome, String kotlinHome, JpsProject project, JpsGlobal global, BuildMessages messages) { - def bundledKotlinPath = "$communityHome/build/dependencies/build/Kotlin/kotlinc" - if (!new File(bundledKotlinPath, "lib/kotlin-runtime.jar").exists()) { - messages.error( - "Could not find Kotlin runtime at $bundledKotlinPath/lib/kotlin-runtime.jar: run `./gradlew setupKotlin` in dependencies module to download Kotlin JARs") - } - JpsModelSerializationDataService.getOrCreatePathVariablesConfiguration(global).addPathVariable("KOTLIN_BUNDLED", bundledKotlinPath) + JpsModelSerializationDataService.getOrCreatePathVariablesConfiguration(global).addPathVariable("KOTLIN_BUNDLED", "$kotlinHome/kotlinc") JdkUtils.defineJdk(global, "IDEA jdk", JdkUtils.computeJdkHome(messages, "jdkHome", "$projectHome/build/jdk/1.6", "JDK_16_x64")) JdkUtils.defineJdk(global, "1.8", jdkHome) @@ -120,10 +121,11 @@ class CompilationContextImpl implements CompilationContext { messages.info("Loaded project $projectHome: ${project.modules.size()} modules, ${project.libraryCollection.libraries.size()} libraries") } - private static void setupDependencies(BuildMessages messages, String communityHome) { - messages.info("Setting up compilation dependencies") - if (!BuildUtils.gradle(new File(communityHome, 'build/dependencies/'), 'setupJdks', 'setupKotlin')) { - messages.error("Cannot setup compilation dependencies") + static boolean dependenciesInstalled + static void setupCompilationDependencies(GradleRunner gradle) { + if (!dependenciesInstalled) { + dependenciesInstalled = true + gradle.run('Setting up compilation dependencies', 'setupJdks', 'setupKotlinPlugin') } } @@ -240,17 +242,18 @@ class CompilationContextImpl implements CompilationContext { messages.artifactBuild(relativePath) } - private static String toCanonicalPath(String communityHome) { - FileUtil.toSystemIndependentName(new File(communityHome).canonicalPath) + private static String toCanonicalPath(String path) { + FileUtil.toSystemIndependentName(new File(path).canonicalPath) } } class BuildPathsImpl extends BuildPaths { - BuildPathsImpl(String communityHome, String projectHome, String buildOutputRoot, String jdkHome) { + BuildPathsImpl(String communityHome, String projectHome, String buildOutputRoot, String jdkHome, String kotlinHome) { this.communityHome = communityHome this.projectHome = projectHome this.buildOutputRoot = buildOutputRoot this.jdkHome = jdkHome + this.kotlinHome = kotlinHome artifacts = "$buildOutputRoot/artifacts" distAll = "$buildOutputRoot/dist.all" temp = "$buildOutputRoot/temp" diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/CompilationTasksImpl.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/CompilationTasksImpl.groovy index 41064c16d540..e006e4dd5e1b 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/CompilationTasksImpl.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/CompilationTasksImpl.groovy @@ -40,6 +40,7 @@ class CompilationTasksImpl extends CompilationTasks { return } + CompilationContextImpl.setupCompilationDependencies(context.gradle) ensureKotlinCompilerAddedToClassPath() context.messages.progress("Compiling project") @@ -77,14 +78,11 @@ class CompilationTasksImpl extends CompilationTasks { } private void ensureKotlinCompilerAddedToClassPath() { - try { - Class.forName("org.jetbrains.kotlin.jps.build.KotlinBuilder") + if (getClass().getResource("/org/jetbrains/kotlin/jps/build/KotlinBuilder.class") != null) { return } - catch (ClassNotFoundException ignored) { - } - def kotlinPluginLibPath = "$context.paths.communityHome/build/dependencies/build/Kotlin/lib" + def kotlinPluginLibPath = "$context.paths.kotlinHome/lib" if (new File(kotlinPluginLibPath).exists()) { ["jps/kotlin-jps-plugin.jar", "kotlin-plugin.jar", "kotlin-runtime.jar", "kotlin-reflect.jar"].each { BuildUtils.addToJpsClassPath("$kotlinPluginLibPath/$it", context.ant) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/PluginLayout.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/PluginLayout.groovy index 7bc8c7646730..31537047e51b 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/PluginLayout.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/PluginLayout.groovy @@ -75,15 +75,18 @@ class PluginLayout extends BaseLayout { static class PluginLayoutSpec extends BaseLayoutSpec { private final PluginLayout layout /** - * Name of the directory (under 'plugins' directory) where the plugin should be placed + * Custom name of the directory (under 'plugins' directory) where the plugin should be placed. By default the main module name is used. + * Don't set this property for new plugins; it is temporary added to keep layout of old plugins unchanged. */ String directoryName /** - * Name of the main plugin JAR file + * Custom name of the main plugin JAR file. By default the main module name with 'jar' extension is used. + * Don't set this property for new plugins; it is temporary added to keep layout of old plugins unchanged. */ String mainJarName /** - * Version of the plugin if it differs from the global build number + * Version of the plugin if it differs from the global build number. + * Don't set this property for new plugins; it is temporary added to keep versioning scheme for some old plugins. */ String version diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TestingTasksImpl.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TestingTasksImpl.groovy index 360b0ba038e0..a3defb89e2ce 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TestingTasksImpl.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TestingTasksImpl.groovy @@ -50,6 +50,7 @@ class TestingTasksImpl extends TestingTasks { else { compilationTasks.compileAllModulesAndTests() } + setupTestingDependencies() def mainModule = options.mainModule ?: defaultMainModule List testsClasspath = context.projectBuilder.moduleRuntimeClasspath(context.findRequiredModule(mainModule), true) @@ -88,8 +89,8 @@ class TestingTasksImpl extends TestingTasks { "idea.home.path" : context.paths.projectHome, "idea.config.path" : "$tempDir/config".toString(), "idea.system.path" : "$tempDir/system".toString(), - "idea.test.patterns" : options.testPatterns, - "idea.test.group" : options.testGroup, + "intellij.build.test.patterns" : options.testPatterns, + "intellij.build.test.groups" : options.testGroups, "idea.performance.tests" : System.getProperty("idea.performance.tests"), "idea.coverage.enabled.build" : System.getProperty("idea.coverage.enabled.build"), "bootstrap.testcases" : "com.intellij.AllTests", @@ -133,7 +134,7 @@ class TestingTasksImpl extends TestingTasks { suspendDebugProcess = false } - context.messages.info("Starting ${options.testGroup != null ? "test from groups '$options.testGroup'" : "all tests"}") + context.messages.info("Starting ${options.testGroups != null ? "test from groups '$options.testGroups'" : "all tests"}") context.messages.info("JVM options: $jvmArgs") context.messages.info("System properties: $systemProperties") context.messages.info("Bootstrap classpath: $bootstrapClasspath") @@ -171,6 +172,14 @@ class TestingTasksImpl extends TestingTasks { test(name: 'com.intellij.tests.BootstrapTests') } } + + static boolean dependenciesInstalled + private def setupTestingDependencies() { + if (!dependenciesInstalled) { + dependenciesInstalled = true + context.gradle.run('Setting up testing dependencies', 'setupKotlinPlugin') + } + } static boolean taskDefined diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy index 5681bb964a61..df85abd7b929 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy @@ -82,7 +82,7 @@ class WindowsDistributionBuilder extends OsSpecificDistributionBuilder { void buildArtifacts(String winDistPath) { def arch = customizer.bundledJreArchitecture def jreDirectoryPath64 = arch != null ? buildContext.bundledJreManager.extractWinJre(arch) : null - List jreDirectoryPaths = [jreDirectoryPath64]; + List jreDirectoryPaths = [jreDirectoryPath64] if (customizer.getBaseDownloadUrlForJre() != null && arch != JvmArchitecture.x32) { File archive = buildContext.bundledJreManager.findWinJreArchive(JvmArchitecture.x32) @@ -94,7 +94,7 @@ class WindowsDistributionBuilder extends OsSpecificDistributionBuilder { include(name: "**/**") } } - jreDirectoryPaths = [jreDirectoryPath64, jreDirectoryPath]; + jreDirectoryPaths = [jreDirectoryPath64, jreDirectoryPath] } } @@ -178,14 +178,14 @@ class WindowsDistributionBuilder extends OsSpecificDistributionBuilder { String vmOptions = "$buildContext.additionalJvmArguments -Didea.paths.selector=${buildContext.systemSelector}".trim() def productName = buildContext.applicationInfo.shortProductName - String jdkEnvVarSuffix = arch == JvmArchitecture.x64 && customizer.include32BitLauncher ? "_64" : ""; + String jdkEnvVarSuffix = arch == JvmArchitecture.x64 && customizer.include32BitLauncher ? "_64" : "" String vmOptionsEnvVarSuffix = arch == JvmArchitecture.x64 && customizer.include32BitLauncher ? "64" : "" def envVarBaseName = buildContext.productProperties.getEnvironmentVariableBaseName(buildContext.applicationInfo) new File(launcherPropertiesPath).text = """ IDS_JDK_ONLY=$buildContext.productProperties.toolsJarRequired IDS_JDK_ENV_VAR=${envVarBaseName}_JDK$jdkEnvVarSuffix IDS_APP_TITLE=$productName Launcher -IDS_VM_OPTIONS_PATH=%USERPROFILE%\\\\.$buildContext.systemSelector +IDS_VM_OPTIONS_PATH=%USERPROFILE%\\\\.$buildContext.systemSelector\\\\config IDS_VM_OPTION_ERRORFILE=-XX:ErrorFile=%USERPROFILE%\\\\java_error_in_${lowerCaseProductName}_%p.log IDS_VM_OPTION_HEAPDUMPPATH=-XX:HeapDumpPath=%USERPROFILE%\\\\java_error_in_${lowerCaseProductName}.hprof IDC_WINLAUNCHER=${upperCaseProductName}_LAUNCHER diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/package.html b/platform/build-scripts/groovy/org/jetbrains/intellij/build/package.html index 1c90a9c31ed0..6e09c78151ab 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/package.html +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/package.html @@ -3,13 +3,16 @@ This package contains groovy scripts which build distributions of products based on IntelliJ Platform.

-If you want to build a product from sources locally, run the corresponding *.gant file from IntelliJ IDEA (e.g. dist.gant to build IDEA Community). +If you want to build a product from sources locally, run the corresponding *.gant file from IntelliJ IDEA (e.g. idea_community.gant to build IDEA Community). Do not forget to add 'Build Project' step to 'Before Launch' section of the created Run configuration to ensure that changed groovy scripts are copied to the output. It makes sense to add {@linkplain org.jetbrains.intellij.build.BuildOptions#USE_COMPILED_CLASSES_PROPERTY '-Dintellij.build.use.compiled.classes=true'} to 'VM Options' to skip compilation and use the compiled classes from the project output. Also you may use {@linkplain org.jetbrains.intellij.build.BuildOptions#targetOS 'intellij.build.target.os'} system property to build artifacts only for a specific OS, and set {@linkplain org.jetbrains.intellij.build.BuildOptions#buildStepsToSkip 'intellij.build.skip.build.steps'} system property to skip some long build steps (e.g. scrambling). See {@link org.jetbrains.intellij.build.BuildOptions BuildOptions} class for more options.

+

+ In order to run a gant script without IntelliJ IDEA you can use build/gant.xml Ant file and pass path to the gant script via gant.script property. +

If you want to add a new module to an existing product, add its name to {@link org.jetbrains.intellij.build.ProductModulesLayout#platformApiModules platformApiModules/platformImplementationModules}. If the module is part of IntelliJ Platform and needs to be included into all products diff --git a/platform/configuration-store-impl/src/SchemeManagerFactoryImpl.kt b/platform/configuration-store-impl/src/SchemeManagerFactoryImpl.kt index e4404d2b837e..ad6728fb8a01 100644 --- a/platform/configuration-store-impl/src/SchemeManagerFactoryImpl.kt +++ b/platform/configuration-store-impl/src/SchemeManagerFactoryImpl.kt @@ -46,7 +46,8 @@ sealed class SchemeManagerFactoryBase : SchemeManagerFactory(), SettingsSavingCo roamingType: RoamingType, isUseOldFileNameSanitize: Boolean, streamProvider: StreamProvider?, - directoryPath: Path?): SchemeManager { + directoryPath: Path?, + autoSave: Boolean): SchemeManager { val path = checkPath(directoryName) val manager = SchemeManagerImpl(path, processor, @@ -56,8 +57,10 @@ sealed class SchemeManagerFactoryBase : SchemeManagerFactory(), SettingsSavingCo presentableName, isUseOldFileNameSanitize, componentManager?.messageBus) - @Suppress("UNCHECKED_CAST") - managers.add(manager as SchemeManagerImpl) + if (autoSave) { + @Suppress("UNCHECKED_CAST") + managers.add(manager as SchemeManagerImpl) + } return manager } diff --git a/platform/configuration-store-impl/src/SchemeManagerImpl.kt b/platform/configuration-store-impl/src/SchemeManagerImpl.kt index e1659325d95a..923b57a21f93 100644 --- a/platform/configuration-store-impl/src/SchemeManagerImpl.kt +++ b/platform/configuration-store-impl/src/SchemeManagerImpl.kt @@ -499,7 +499,7 @@ class SchemeManagerImpl(val fileSpec: String, return null } - fun save(errors: MutableList) { + override fun save(errors: MutableList) { if (isLoadingSchemes.get()) { LOG.warn("Skip save - schemes are loading") } @@ -625,7 +625,7 @@ class SchemeManagerImpl(val fileSpec: String, } // if another new scheme uses old name of this scheme, we must not delete it (as part of rename operation) - val renamed = externalInfo != null && fileNameWithoutExtension !== currentFileNameWithoutExtension && nameGenerator.isUnique(currentFileNameWithoutExtension) + val renamed = externalInfo != null && fileNameWithoutExtension !== currentFileNameWithoutExtension && currentFileNameWithoutExtension != null && nameGenerator.isUnique(currentFileNameWithoutExtension) if (providerPath == null) { if (useVfs) { var file: VirtualFile? = null diff --git a/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt b/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt index ca05131e9257..f081c73cbc22 100644 --- a/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt +++ b/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt @@ -24,12 +24,10 @@ import com.intellij.testFramework.PlatformTestUtil import com.intellij.testFramework.ProjectRule import com.intellij.testFramework.TemporaryDirectory import com.intellij.testFramework.runInEdtAndWait -import com.intellij.util.SmartList import com.intellij.util.io.createDirectories import com.intellij.util.io.directoryStreamIfExists import com.intellij.util.io.readText import com.intellij.util.io.write -import com.intellij.util.lang.CompoundRuntimeException import com.intellij.util.loadElement import com.intellij.util.toByteArray import com.intellij.util.xmlb.annotations.Tag @@ -443,10 +441,4 @@ open class TestSchemesProcessor : LazySchemeProcessor() dataHolder.updateDigest(scheme) return scheme } -} - -fun SchemeManagerImpl<*, *>.save() { - val errors = SmartList() - save(errors) - CompoundRuntimeException.throwIfNotEmpty(errors) } \ No newline at end of file diff --git a/platform/core-api/src/com/intellij/codeInsight/folding/CodeFoldingSettings.java b/platform/core-api/src/com/intellij/codeInsight/folding/CodeFoldingSettings.java index 0e4dbaa7137c..7c5c1d1299e9 100644 --- a/platform/core-api/src/com/intellij/codeInsight/folding/CodeFoldingSettings.java +++ b/platform/core-api/src/com/intellij/codeInsight/folding/CodeFoldingSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. diff --git a/platform/core-api/src/com/intellij/lang/folding/CustomFoldingProvider.java b/platform/core-api/src/com/intellij/lang/folding/CustomFoldingProvider.java index 8c6b63223783..71840aedefdc 100644 --- a/platform/core-api/src/com/intellij/lang/folding/CustomFoldingProvider.java +++ b/platform/core-api/src/com/intellij/lang/folding/CustomFoldingProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2017 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. diff --git a/platform/core-api/src/com/intellij/lang/folding/FoldingDescriptor.java b/platform/core-api/src/com/intellij/lang/folding/FoldingDescriptor.java index bb3edbdb5b48..cb190947e7f8 100644 --- a/platform/core-api/src/com/intellij/lang/folding/FoldingDescriptor.java +++ b/platform/core-api/src/com/intellij/lang/folding/FoldingDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -30,6 +30,11 @@ import java.util.Set; /** * Defines a single folding region in the code. * + *

Dependencies

+ * Dependencies are objects (in particular, instances of {@link com.intellij.openapi.util.ModificationTracker}, + * more info - {@link com.intellij.psi.util.CachedValueProvider.Result#getDependencyItems here}), + * which can be tracked for changes, that should trigger folding regions recalculation for an editor (initiating code folding pass). + * * @author max * @see FoldingBuilder */ @@ -47,8 +52,8 @@ public class FoldingDescriptor { * Creates a folding region related to the specified AST node and covering the specified * text range. * @param node The node to which the folding region is related. The node is then passed to - * {@link FoldingBuilder#getPlaceholderText(com.intellij.lang.ASTNode)} and - * {@link FoldingBuilder#isCollapsedByDefault(com.intellij.lang.ASTNode)}. + * {@link FoldingBuilder#getPlaceholderText(ASTNode)} and + * {@link FoldingBuilder#isCollapsedByDefault(ASTNode)}. * @param range The folded text range. */ public FoldingDescriptor(@NotNull ASTNode node, @NotNull TextRange range) { @@ -63,25 +68,25 @@ public class FoldingDescriptor { * Creates a folding region related to the specified AST node and covering the specified * text range. * @param node The node to which the folding region is related. The node is then passed to - * {@link FoldingBuilder#getPlaceholderText(com.intellij.lang.ASTNode)} and - * {@link FoldingBuilder#isCollapsedByDefault(com.intellij.lang.ASTNode)}. + * {@link FoldingBuilder#getPlaceholderText(ASTNode)} and + * {@link FoldingBuilder#isCollapsedByDefault(ASTNode)}. * @param range The folded text range. * @param group Regions with the same group instance expand and collapse together. */ public FoldingDescriptor(@NotNull ASTNode node, @NotNull TextRange range, @Nullable FoldingGroup group) { - this(node, range, group, Collections.emptySet()); + this(node, range, group, Collections.emptySet()); } /** * Creates a folding region related to the specified AST node and covering the specified * text range. * @param node The node to which the folding region is related. The node is then passed to - * {@link com.intellij.lang.folding.FoldingBuilder#getPlaceholderText(com.intellij.lang.ASTNode)} and - * {@link com.intellij.lang.folding.FoldingBuilder#isCollapsedByDefault(com.intellij.lang.ASTNode)}. + * {@link FoldingBuilder#getPlaceholderText(ASTNode)} and + * {@link FoldingBuilder#isCollapsedByDefault(ASTNode)}. * @param range The folded text range. * @param group Regions with the same group instance expand and collapse together. * @param dependencies folding dependencies: other files or elements that could change - * folding description + * folding description, see Dependencies */ public FoldingDescriptor(@NotNull ASTNode node, @NotNull TextRange range, @Nullable FoldingGroup group, Set dependencies) { this(node, range, group, dependencies, false); @@ -91,11 +96,11 @@ public class FoldingDescriptor { * Creates a folding region related to the specified AST node and covering the specified * text range. * @param node The node to which the folding region is related. The node is then passed to - * {@link com.intellij.lang.folding.FoldingBuilder#getPlaceholderText(com.intellij.lang.ASTNode)} and - * {@link com.intellij.lang.folding.FoldingBuilder#isCollapsedByDefault(com.intellij.lang.ASTNode)}. + * {@link FoldingBuilder#getPlaceholderText(ASTNode)} and + * {@link FoldingBuilder#isCollapsedByDefault(ASTNode)}. * @param range The folded text range. * @param group Regions with the same group instance expand and collapse together. - * @param dependencies folding dependencies: other files or elements that could change + * @param dependencies folding dependencies: other files or elements that could change, see Dependencies * @param neverExpands shall be true for fold regions that must not be ever expanded. */ public FoldingDescriptor(@NotNull ASTNode node, diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileListener.java b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileListener.java index 675a352072db..99f98eb79da1 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileListener.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileListener.java @@ -73,6 +73,7 @@ public interface VirtualFileListener extends EventListener { * @param event the event object containing information about the change. */ default void fileCopied(@NotNull VirtualFileCopyEvent event) { + fileCreated(event); } /** diff --git a/platform/core-api/src/com/intellij/psi/PsiLanguageInjectionHost.java b/platform/core-api/src/com/intellij/psi/PsiLanguageInjectionHost.java index bc447903aa84..ea89efe4101c 100644 --- a/platform/core-api/src/com/intellij/psi/PsiLanguageInjectionHost.java +++ b/platform/core-api/src/com/intellij/psi/PsiLanguageInjectionHost.java @@ -45,7 +45,7 @@ public interface PsiLanguageInjectionHost extends PsiElement { /** * Update the host element using the provided text of the injected file. It may be required to escape characters from {@code text} - * in accordance with the host language syntax. The implementation may delegate to {@link com.intellij.psi.ElementManipulators#handleContentChange(PsiElement, String)} + * in accordance with the host language syntax. The implementation may delegate to {@link ElementManipulators#handleContentChange(PsiElement, String)} * if {@link com.intellij.psi.ElementManipulator} implementation is registered for this element class * @param text text of the injected file * @return the updated instance @@ -59,6 +59,7 @@ public interface PsiLanguageInjectionHost extends PsiElement { LiteralTextEscaper createLiteralTextEscaper(); + @FunctionalInterface interface InjectedPsiVisitor { void visit(@NotNull PsiFile injectedPsi, @NotNull List places); } diff --git a/platform/core-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java b/platform/core-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java index 481762a0740a..eb4ada17ecc7 100644 --- a/platform/core-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java +++ b/platform/core-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java @@ -278,6 +278,15 @@ public abstract class CodeStyleManager { return -1; } + /** + * Calculates minimum number of line feeds that should precede block starting at given offset, as dictated by formatting model. + * Returns -1, if required block cannot be found at provided offset, + * or spacing cannot be calculated due to some other reason. + */ + public int getMinLineFeeds(@NotNull PsiFile file, int offset) { + return -1; + } + /** * Retrieves the current formatting mode. * diff --git a/platform/core-api/src/com/intellij/psi/stubs/EmptyStubElementType.java b/platform/core-api/src/com/intellij/psi/stubs/EmptyStubElementType.java index 634b491854b3..6fcba842d7b3 100644 --- a/platform/core-api/src/com/intellij/psi/stubs/EmptyStubElementType.java +++ b/platform/core-api/src/com/intellij/psi/stubs/EmptyStubElementType.java @@ -31,6 +31,7 @@ public abstract class EmptyStubElementType extends IStubEl super(debugName, language); } + @NotNull @Override public final EmptyStub createStub(@NotNull T psi, StubElement parentStub) { return createStub(parentStub); diff --git a/platform/core-api/src/com/intellij/psi/stubs/IStubElementType.java b/platform/core-api/src/com/intellij/psi/stubs/IStubElementType.java index bb3f87afa3b7..cfe36c13d63d 100644 --- a/platform/core-api/src/com/intellij/psi/stubs/IStubElementType.java +++ b/platform/core-api/src/com/intellij/psi/stubs/IStubElementType.java @@ -22,24 +22,32 @@ package com.intellij.psi.stubs; import com.intellij.lang.ASTNode; import com.intellij.lang.Language; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.Extensions; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; + public abstract class IStubElementType extends IElementType implements StubSerializer { - private static boolean ourInitializedStubs; + private static volatile boolean ourInitializedStubs; private static final Logger LOG = Logger.getInstance("#com.intellij.psi.stubs.IStubElementType"); public IStubElementType(@NotNull @NonNls final String debugName, @Nullable final Language language) { super(debugName, language); if (ourInitializedStubs) { - LOG.error("All stub element types should be created before index initialization is complete. Please add the class containing stub element type constants to \"stubElementTypeHolder\" extension."); + LOG.error("All stub element types should be created before index initialization is complete.\n" + + "Please add the class containing stub element type constants to \"stubElementTypeHolder\" extension.\n" + + "Registered extensions: " + Arrays.toString(StubElementTypeHolderEP.EP_NAME.getExtensions())); } } - static void markStubInitializationComplete() { + static void loadRegisteredStubElementTypes() { + for (StubElementTypeHolderEP holderEP : Extensions.getExtensions(StubElementTypeHolderEP.EP_NAME)) { + holderEP.initialize(); + } ourInitializedStubs = true; } diff --git a/platform/indexing-api/src/com/intellij/psi/stubs/StubElementTypeHolderEP.java b/platform/core-api/src/com/intellij/psi/stubs/StubElementTypeHolderEP.java similarity index 92% rename from platform/indexing-api/src/com/intellij/psi/stubs/StubElementTypeHolderEP.java rename to platform/core-api/src/com/intellij/psi/stubs/StubElementTypeHolderEP.java index 9d4f64ff1429..60fee521c764 100644 --- a/platform/indexing-api/src/com/intellij/psi/stubs/StubElementTypeHolderEP.java +++ b/platform/core-api/src/com/intellij/psi/stubs/StubElementTypeHolderEP.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -40,4 +40,9 @@ public class StubElementTypeHolderEP extends AbstractExtensionPointBean { LOG.error(e); } } + + @Override + public String toString() { + return holderClass; + } } diff --git a/platform/core-api/src/com/intellij/psi/tree/IElementType.java b/platform/core-api/src/com/intellij/psi/tree/IElementType.java index 2a8f8a6c27b5..f468e70abfb7 100644 --- a/platform/core-api/src/com/intellij/psi/tree/IElementType.java +++ b/platform/core-api/src/com/intellij/psi/tree/IElementType.java @@ -40,24 +40,21 @@ public class IElementType { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.tree.IElementType"); public static final IElementType[] EMPTY_ARRAY = new IElementType[0]; + public static final ArrayFactory ARRAY_FACTORY = count -> count == 0 ? EMPTY_ARRAY : new IElementType[count]; /** * Default enumeration predicate which matches all token types. * * @see #enumerate(Predicate) */ - public static final Predicate TRUE = new Predicate() { - @Override - public boolean matches(@NotNull IElementType type) { - return true; - } - }; + public static final Predicate TRUE = type -> true; public static final short FIRST_TOKEN_INDEX = 1; private static final short MAX_INDEXED_TYPES = 15000; private static short size; // guarded by lock private static volatile IElementType[] ourRegistry = EMPTY_ARRAY; // writes are guarded by lock + @SuppressWarnings("RedundantStringConstructorCall") private static final Object lock = new String("registry lock"); static { @@ -91,7 +88,6 @@ public class IElementType { this(debugName, language, true); } - private static final ArrayFactory FACTORY = count -> new IElementType[count]; /** * Allows to construct element types for some temporary purposes without registering them. @@ -107,7 +103,7 @@ public class IElementType { myIndex = size++; LOG.assertTrue(myIndex < MAX_INDEXED_TYPES, "Too many element types registered. Out of (short) range."); IElementType[] newRegistry = - myIndex >= ourRegistry.length ? ArrayUtil.realloc(ourRegistry, ourRegistry.length * 3 / 2 + 1, FACTORY) : ourRegistry; + myIndex >= ourRegistry.length ? ArrayUtil.realloc(ourRegistry, ourRegistry.length * 3 / 2 + 1, ARRAY_FACTORY) : ourRegistry; newRegistry[myIndex] = this; ourRegistry = newRegistry; } @@ -189,6 +185,7 @@ public class IElementType { * * @see IElementType#enumerate(Predicate) */ + @FunctionalInterface public interface Predicate { boolean matches(@NotNull IElementType type); } diff --git a/platform/core-api/src/com/intellij/usageView/UsageInfo.java b/platform/core-api/src/com/intellij/usageView/UsageInfo.java index 2881d761b00b..78c1d854c196 100644 --- a/platform/core-api/src/com/intellij/usageView/UsageInfo.java +++ b/platform/core-api/src/com/intellij/usageView/UsageInfo.java @@ -35,7 +35,7 @@ public class UsageInfo { public final boolean isNonCodeUsage; protected boolean myDynamicUsage; - public UsageInfo(@NotNull PsiElement element, int startOffset, int endOffset, boolean isNonCodeUsage) { + public UsageInfo(@NotNull PsiElement element, final int startOffset, final int endOffset, boolean isNonCodeUsage) { element = element.getNavigationElement(); PsiFile file = element.getContainingFile(); PsiElement topElement = file == null ? element : file; @@ -45,30 +45,32 @@ public class UsageInfo { if (elementRange == null) { throw new IllegalArgumentException("text range null for " + element + "; " + element.getClass()); } + int effectiveStart; + int effectiveEnd; if (startOffset == -1 && endOffset == -1) { // calculate natural element range - startOffset = element.getTextOffset() - elementRange.getStartOffset(); - endOffset = elementRange.getEndOffset() - elementRange.getStartOffset(); + effectiveStart = element.getTextOffset() - elementRange.getStartOffset(); + effectiveEnd = elementRange.getLength(); + } + else { + effectiveStart = startOffset; + effectiveEnd = endOffset; } - if (startOffset < 0) { - throw new IllegalArgumentException("element " + element + "; startOffset " +startOffset); - } - if (startOffset > endOffset) { - throw new IllegalArgumentException("element " + element + "; diff " + (endOffset-startOffset)); + if (effectiveStart < 0 || effectiveStart > effectiveEnd) { + throw new IllegalArgumentException("element " + element + "; startOffset " +startOffset+"; endOffset="+endOffset+ + "; effectiveStart="+effectiveStart+"; effectiveEnd="+effectiveEnd+ + "; elementRange="+elementRange+"; element.getTextOffset()="+element.getTextOffset()); } Project project = topElement.getProject(); SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(project); mySmartPointer = smartPointerManager.createSmartPsiElementPointer(element, file); - if (startOffset != element.getTextOffset() - elementRange.getStartOffset() || endOffset != elementRange.getLength()) { - TextRange rangeToStore; - if (file != null && InjectedLanguageManager.getInstance(project).isInjectedFragment(file)) { - rangeToStore = elementRange; - } - else { - rangeToStore = TextRange.create(startOffset, endOffset).shiftRight(elementRange.getStartOffset()); - } + if (file != null && + (effectiveStart != element.getTextOffset() - elementRange.getStartOffset() || effectiveEnd != elementRange.getLength())) { + TextRange rangeToStore = InjectedLanguageManager.getInstance(project).isInjectedFragment(file) + ? elementRange + : TextRange.create(effectiveStart, effectiveEnd).shiftRight(elementRange.getStartOffset()); myPsiFileRange = smartPointerManager.createSmartPsiFileRangePointer(file, rangeToStore); } else { diff --git a/platform/core-impl/src/com/intellij/lang/folding/NamedFoldingDescriptor.java b/platform/core-impl/src/com/intellij/lang/folding/NamedFoldingDescriptor.java index abf78e50061e..4bc71780af6c 100644 --- a/platform/core-impl/src/com/intellij/lang/folding/NamedFoldingDescriptor.java +++ b/platform/core-impl/src/com/intellij/lang/folding/NamedFoldingDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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,6 +22,10 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** + * A variant of {@link FoldingDescriptor} which keeps precalculated value of placeholder text. + * This makes 'apply' phase of code folding pass (executed in EDT) faster. + */ public class NamedFoldingDescriptor extends FoldingDescriptor { private final String myPlaceholderText; diff --git a/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java b/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java index 65947401313e..3434df2dcb14 100644 --- a/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java +++ b/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -126,8 +126,6 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { doneMarker.clean(); } }); - private static final ArrayFactory myElementTypeArrayFactory = - count -> count == 0 ? IElementType.EMPTY_ARRAY : new IElementType[count]; public static void registerWhitespaceToken(@NotNull IElementType type) { ourAnyLanguageWhitespaceTokens = TokenSet.orSet(ourAnyLanguageWhitespaceTokens, TokenSet.create(type)); @@ -266,9 +264,10 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { int i = 0; int offset = 0; while (true) { - ProgressIndicatorProvider.checkCanceled(); IElementType type = myLexer.getTokenType(); if (type == null) break; + + if (i % 20 == 0) ProgressIndicatorProvider.checkCanceled(); if (i >= myLexTypes.length - 1) { resizeLexemes(i * 3 / 2); @@ -918,7 +917,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { private void resizeLexemes(final int newSize) { myLexStarts = ArrayUtil.realloc(myLexStarts, newSize+1); - myLexTypes = ArrayUtil.realloc(myLexTypes, newSize, myElementTypeArrayFactory); + myLexTypes = ArrayUtil.realloc(myLexTypes, newSize, IElementType.ARRAY_FACTORY); clearCachedTokenType(); } diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/InjectedSelfElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/InjectedSelfElementInfo.java index 7c1c9f3d6127..44c56393d5e6 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/InjectedSelfElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/InjectedSelfElementInfo.java @@ -122,16 +122,13 @@ class InjectedSelfElementInfo extends SmartPointerElementInfo { @NotNull final TextRange rangeInHostFile) { final PsiDocumentManagerBase docManager = (PsiDocumentManagerBase)PsiDocumentManager.getInstance(getProject()); final PsiFile[] result = {null}; - final PsiLanguageInjectionHost.InjectedPsiVisitor visitor = new PsiLanguageInjectionHost.InjectedPsiVisitor() { - @Override - public void visit(@NotNull PsiFile injectedPsi, @NotNull List places) { - Document document = docManager.getDocument(injectedPsi); - if (document instanceof DocumentWindow) { - DocumentWindow window = (DocumentWindow)docManager.getLastCommittedDocument(document); - TextRange hostRange = window.injectedToHost(new TextRange(0, injectedPsi.getTextLength())); - if (hostRange.contains(rangeInHostFile)) { - result[0] = injectedPsi; - } + final PsiLanguageInjectionHost.InjectedPsiVisitor visitor = (injectedPsi, places) -> { + Document document = docManager.getDocument(injectedPsi); + if (document instanceof DocumentWindow) { + DocumentWindow window = (DocumentWindow)docManager.getLastCommittedDocument(document); + TextRange hostRange = window.injectedToHost(new TextRange(0, injectedPsi.getTextLength())); + if (hostRange.contains(rangeInHostFile)) { + result[0] = injectedPsi; } } }; @@ -142,7 +139,7 @@ class InjectedSelfElementInfo extends SmartPointerElementInfo { for (DocumentWindow documentWindow : InjectedLanguageManager.getInstance(getProject()).getCachedInjectedDocuments(hostFile)) { PsiFile injected = documentManager.getPsiFile(documentWindow); if (injected != null) { - visitor.visit(injected, Collections.emptyList()); + visitor.visit(injected, Collections.emptyList()); } } } @@ -151,7 +148,7 @@ class InjectedSelfElementInfo extends SmartPointerElementInfo { if (injected != null) { for (Pair pair : injected) { PsiFile injectedFile = pair.first.getContainingFile(); - visitor.visit(injectedFile, ContainerUtil.emptyList()); + visitor.visit(injectedFile, ContainerUtil.emptyList()); } } } @@ -162,7 +159,7 @@ class InjectedSelfElementInfo extends SmartPointerElementInfo { @Override public boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other) { if (getClass() != other.getClass()) return false; - if (!(((InjectedSelfElementInfo)other).myHostContext).equals(myHostContext)) return false; + if (!((InjectedSelfElementInfo)other).myHostContext.equals(myHostContext)) return false; SmartPointerElementInfo myElementInfo = ((SmartPsiElementPointerImpl)myInjectedFileRangeInHostFile).getElementInfo(); SmartPointerElementInfo oElementInfo = ((SmartPsiElementPointerImpl)((InjectedSelfElementInfo)other).myInjectedFileRangeInHostFile).getElementInfo(); return myElementInfo.pointsToTheSameElementAs(oElementInfo); diff --git a/platform/core-impl/src/com/intellij/util/CachedValueLeakChecker.java b/platform/core-impl/src/com/intellij/util/CachedValueLeakChecker.java index 0e8ddb7c5d44..531a2f3bea72 100644 --- a/platform/core-impl/src/com/intellij/util/CachedValueLeakChecker.java +++ b/platform/core-impl/src/com/intellij/util/CachedValueLeakChecker.java @@ -43,7 +43,6 @@ class CachedValueLeakChecker { private static final Logger LOG = Logger.getInstance("#com.intellij.util.CachedValueChecker"); private static final boolean DO_CHECKS = ApplicationManager.getApplication().isUnitTestMode(); private static final Set ourCheckedKeys = ContainerUtil.newConcurrentSet(); - private static final boolean JAVA9 = SystemInfo.isJavaVersionAtLeast("9"); static void checkProvider(@NotNull final CachedValueProvider provider, @NotNull final Key key, @@ -51,7 +50,7 @@ class CachedValueLeakChecker { if (!DO_CHECKS || ApplicationInfoImpl.isInStressTest()) return; if (!ourCheckedKeys.add(key.toString())) return; // store strings because keys are created afresh in each (test) project - if (!JAVA9) { + if (!SystemInfo.IS_AT_LEAST_JAVA9) { findReferencedPsi(provider, userDataHolder, 5); } } diff --git a/platform/diff-api/src/com/intellij/diff/DiffRequestFactory.java b/platform/diff-api/src/com/intellij/diff/DiffRequestFactory.java index 15e6f31bc515..5d05b7e3439d 100644 --- a/platform/diff-api/src/com/intellij/diff/DiffRequestFactory.java +++ b/platform/diff-api/src/com/intellij/diff/DiffRequestFactory.java @@ -63,7 +63,7 @@ public abstract class DiffRequestFactory { public abstract String getContentTitle(@NotNull VirtualFile file); @NotNull - public abstract String getTitle(@NotNull VirtualFile file1, @NotNull VirtualFile file2); + public abstract String getTitle(@Nullable VirtualFile file1, @Nullable VirtualFile file2); @NotNull public abstract String getTitle(@NotNull VirtualFile file); diff --git a/platform/diff-impl/diff-tests.iml b/platform/diff-impl/diff-tests.iml index a378b2dfcfd9..7178eefe85a3 100644 --- a/platform/diff-impl/diff-tests.iml +++ b/platform/diff-impl/diff-tests.iml @@ -16,5 +16,6 @@ + \ No newline at end of file diff --git a/platform/diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java b/platform/diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java index 98dc253fb707..60b428a6116b 100644 --- a/platform/diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java @@ -45,6 +45,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import static com.intellij.util.ObjectUtils.chooseNotNull; + public class DiffRequestFactoryImpl extends DiffRequestFactory { private final DiffContentFactoryEx myContentFactory = DiffContentFactoryEx.getInstanceEx(); @@ -109,14 +111,16 @@ public class DiffRequestFactoryImpl extends DiffRequestFactory { @NotNull @Override - public String getTitle(@NotNull VirtualFile file1, @NotNull VirtualFile file2) { - return getTitle(VcsUtil.getFilePath(file1), VcsUtil.getFilePath(file2), " vs "); + public String getTitle(@Nullable VirtualFile file1, @Nullable VirtualFile file2) { + FilePath path1 = file1 != null ? VcsUtil.getFilePath(file1) : null; + FilePath path2 = file2 != null ? VcsUtil.getFilePath(file2) : null; + return getTitle(path1, path2, " vs "); } @NotNull @Override public String getTitle(@NotNull VirtualFile file) { - return getTitle(file, file); + return getTitle(file, null); } @NotNull @@ -127,7 +131,13 @@ public class DiffRequestFactoryImpl extends DiffRequestFactory { } @NotNull - public static String getTitle(@NotNull FilePath path1, @NotNull FilePath path2, @NotNull String separator) { + public static String getTitle(@Nullable FilePath path1, @Nullable FilePath path2, @NotNull String separator) { + assert path1 != null || path2 != null; + + if (path1 == null || path2 == null) { + return getContentTitle(chooseNotNull(path1, path2)); + } + if ((path1.isDirectory() || path2.isDirectory()) && path1.getPath().equals(path2.getPath())) { return path1.getPresentableUrl(); } diff --git a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java index 7d1274659e29..cdecff9a2af6 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java @@ -243,10 +243,10 @@ public class TextMergeViewer implements MergeTool.MergeViewer { group.add(myEditorSettingsAction); DefaultActionGroup diffGroup = new DefaultActionGroup("Compare With", true); - diffGroup.getTemplatePresentation().setIcon(AllIcons.Diff.Diff); - diffGroup.add(new TextShowPartialDiffAction(PartialDiffMode.LEFT_MIDDLE)); - diffGroup.add(new TextShowPartialDiffAction(PartialDiffMode.RIGHT_MIDDLE)); - diffGroup.add(new TextShowPartialDiffAction(PartialDiffMode.LEFT_RIGHT)); + diffGroup.getTemplatePresentation().setIcon(AllIcons.Actions.Diff); + diffGroup.add(new TextShowPartialDiffAction(PartialDiffMode.LEFT_MIDDLE, true)); + diffGroup.add(new TextShowPartialDiffAction(PartialDiffMode.RIGHT_MIDDLE, true)); + diffGroup.add(new TextShowPartialDiffAction(PartialDiffMode.LEFT_RIGHT, true)); diffGroup.add(new ShowDiffWithBaseAction(ThreeSide.LEFT)); diffGroup.add(new ShowDiffWithBaseAction(ThreeSide.BASE)); diffGroup.add(new ShowDiffWithBaseAction(ThreeSide.RIGHT)); diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java index 8b96b57d2f5d..3e2c1321c9a0 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java @@ -64,9 +64,9 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx { group.add(myEditorSettingsAction); group.add(Separator.getInstance()); - group.add(new TextShowPartialDiffAction(PartialDiffMode.MIDDLE_LEFT)); - group.add(new TextShowPartialDiffAction(PartialDiffMode.MIDDLE_RIGHT)); - group.add(new TextShowPartialDiffAction(PartialDiffMode.LEFT_RIGHT)); + group.add(new TextShowPartialDiffAction(PartialDiffMode.MIDDLE_LEFT, false)); + group.add(new TextShowPartialDiffAction(PartialDiffMode.MIDDLE_RIGHT, false)); + group.add(new TextShowPartialDiffAction(PartialDiffMode.LEFT_RIGHT, false)); group.add(Separator.getInstance()); group.addAll(super.createToolbarActions()); diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideDiffViewer.java index d66e650b6027..c8f9a3722fee 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideDiffViewer.java @@ -30,6 +30,7 @@ import com.intellij.diff.tools.util.SimpleDiffPanel; import com.intellij.diff.tools.util.base.ListenerDiffViewerBase; import com.intellij.diff.util.DiffUtil; import com.intellij.diff.util.ThreeSide; +import com.intellij.icons.AllIcons; import com.intellij.idea.ActionsBundle; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.ex.ActionUtil; @@ -196,39 +197,46 @@ public abstract class ThreesideDiffViewer extends Listen @NotNull protected final ThreeSide mySide1; @NotNull protected final ThreeSide mySide2; - public ShowPartialDiffAction(@NotNull PartialDiffMode mode) { + public ShowPartialDiffAction(@NotNull PartialDiffMode mode, boolean hasFourSides) { String id; + Icon icon = null; switch (mode) { case LEFT_MIDDLE: mySide1 = ThreeSide.LEFT; mySide2 = ThreeSide.BASE; id = "Diff.ComparePartial.Base.Left"; + if (!hasFourSides) icon = AllIcons.Diff.LeftDiff; break; case RIGHT_MIDDLE: mySide1 = ThreeSide.RIGHT; mySide2 = ThreeSide.BASE; id = "Diff.ComparePartial.Base.Right"; + if (!hasFourSides) icon = AllIcons.Diff.RightDiff; break; case MIDDLE_LEFT: mySide1 = ThreeSide.BASE; mySide2 = ThreeSide.LEFT; id = "Diff.ComparePartial.Base.Left"; + if (!hasFourSides) icon = AllIcons.Diff.LeftDiff; break; case MIDDLE_RIGHT: mySide1 = ThreeSide.BASE; mySide2 = ThreeSide.RIGHT; id = "Diff.ComparePartial.Base.Right"; + if (!hasFourSides) icon = AllIcons.Diff.RightDiff; break; case LEFT_RIGHT: mySide1 = ThreeSide.LEFT; mySide2 = ThreeSide.RIGHT; id = "Diff.ComparePartial.Left.Right"; + if (!hasFourSides) icon = AllIcons.Diff.BranchDiff; break; default: throw new IllegalArgumentException(); } String text = ActionsBundle.message("action.Diff.ComparePartial.Generic", mySide1.getIndex(), mySide2.getIndex()); getTemplatePresentation().setText(text); + getTemplatePresentation().setIcon(icon); ActionUtil.mergeFrom(this, id); } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideTextDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideTextDiffViewer.java index cfc8727b16ab..2cb02c6348e4 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideTextDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideTextDiffViewer.java @@ -364,8 +364,8 @@ public abstract class ThreesideTextDiffViewer extends ThreesideDiffViewer loadDiffFrameImages() { return ContainerUtil.list( - ImageLoader.loadFromResource("/diff_frame16.png"), ImageLoader.loadFromResource("/diff_frame32.png"), ImageLoader.loadFromResource("/diff_frame64.png"), ImageLoader.loadFromResource("/diff_frame128.png") diff --git a/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt b/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt index 6bcb79123e0c..b7f8b320e797 100644 --- a/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt +++ b/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt @@ -23,6 +23,7 @@ import com.intellij.openapi.progress.DumbProgressIndicator import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.util.text.StringUtil +import com.intellij.openapi.vcs.LocalFilePath import com.intellij.testFramework.UsefulTestCase import com.intellij.util.containers.HashMap import com.intellij.util.text.CharSequenceSubSequence @@ -115,6 +116,18 @@ abstract class DiffTestCase : TestCase() { } } + fun assertSetsEquals(expected: BitSet, actual: BitSet, message: String = "") { + val sb = StringBuilder(message) + sb.append(": \"") + for (i in 0..actual.length()) { + sb.append(if (actual[i]) '-' else ' ') + } + sb.append('"') + val fullMessage = sb.toString() + + assertEquals(expected, actual, fullMessage) + } + // // Parsing // @@ -140,7 +153,7 @@ abstract class DiffTestCase : TestCase() { return Math.max(1, document.lineCount) } - infix fun Int.until(a: Int): IntRange = this..a - 1 + fun createFilePath(path: String) = LocalFilePath(path, path.endsWith('/') || path.endsWith('\\')) // // AutoTests @@ -210,7 +223,7 @@ abstract class DiffTestCase : TestCase() { } } - class DebugData() { + class DebugData { private val data: MutableList> = ArrayList() fun put(key: String, value: Any) { diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonMergeUtilTestBase.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonMergeUtilTestBase.kt index c116de58652e..249bf8674e48 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonMergeUtilTestBase.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonMergeUtilTestBase.kt @@ -73,12 +73,12 @@ abstract class ComparisonMergeUtilTestBase : DiffTestCase() { val sets = Trio(BitSet(), BitSet(), BitSet()) for (change in changes) { - sets.forEach({ set: BitSet, side: ThreeSide -> set.set(change.start(side), change.end(side)) }) + sets.forEach { set: BitSet, side: ThreeSide -> set.set(change.start(side), change.end(side)) } } - assertEquals(matchings.data1, sets.data1) - assertEquals(matchings.data2, sets.data2) - assertEquals(matchings.data3, sets.data3) + assertSetsEquals(matchings.data1, sets.data1, "Left") + assertSetsEquals(matchings.data2, sets.data2, "Base") + assertSetsEquals(matchings.data3, sets.data3, "Right") } private fun convertDiffFragments(fragments: List): List { diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt index c415aa47ae47..b117f7261577 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt @@ -198,8 +198,8 @@ class ComparisonUtilAutoTest : DiffTestCase() { for (fragment in fragments) { if (fragment.innerFragments != null) { - val sequence1 = text1.subsequence(fragment.startOffset1, fragment.endOffset1) - val sequence2 = text2.subsequence(fragment.startOffset2, fragment.endOffset2) + val sequence1 = text1.subSequence(fragment.startOffset1, fragment.endOffset1) + val sequence2 = text2.subSequence(fragment.startOffset2, fragment.endOffset2) checkResultWord(sequence1, sequence2, fragment.innerFragments!!, policy) } @@ -538,7 +538,7 @@ class ComparisonUtilAutoTest : DiffTestCase() { return Couple.of(firstLine, lastLine) } - private fun Document.subsequence(start: Int, end: Int): CharSequence { + private fun Document.subSequence(start: Int, end: Int): CharSequence { return this.charsSequence.subSequence(start, end) } diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilTestBase.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilTestBase.kt index 9d9bf6796202..f8750fc000dc 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilTestBase.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilTestBase.kt @@ -173,8 +173,8 @@ abstract class ComparisonUtilTestBase : DiffTestCase() { set2.set(fragment.startLine2, fragment.endLine2) } - assertEquals(matchings.first, set1, "Before") - assertEquals(matchings.second, set2, "After") + assertSetsEquals(matchings.first, set1, "Before") + assertSetsEquals(matchings.second, set2, "After") } private fun checkDiffMatching(fragments: List, matchings: Couple) { @@ -185,8 +185,8 @@ abstract class ComparisonUtilTestBase : DiffTestCase() { set2.set(fragment.startOffset2, fragment.endOffset2) } - assertEquals(matchings.first, set1, "Before") - assertEquals(matchings.second, set2, "After") + assertSetsEquals(matchings.first, set1, "Before") + assertSetsEquals(matchings.second, set2, "After") } private fun checkMergeMatching(fragments: List, matchings: Trio) { @@ -199,9 +199,9 @@ abstract class ComparisonUtilTestBase : DiffTestCase() { set3.set(fragment.getStartOffset(ThreeSide.RIGHT), fragment.getEndOffset(ThreeSide.RIGHT)) } - assertEquals(matchings.data1, set1, "Before") - assertEquals(matchings.data2, set2, "Base") - assertEquals(matchings.data3, set3, "After") + assertSetsEquals(matchings.data1, set1, "Left") + assertSetsEquals(matchings.data2, set2, "Base") + assertSetsEquals(matchings.data3, set3, "Right") } private fun convertDiffFragments(fragments: List): List> { diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/IgnoreComparisonUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/IgnoreComparisonUtilTest.kt index fce98b3c2574..825437f5cd43 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/IgnoreComparisonUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/IgnoreComparisonUtilTest.kt @@ -401,28 +401,17 @@ class IgnoreComparisonUtilTest : DiffTestCase() { .run() } - private inner class Test(input1: String, input2: String, + private inner class Test(val input1: String, val input2: String, ignored1: String, ignored2: String, result1: String, result2: String) { - private val input1: String - private val input2: String - private val ignored1: String - private val ignored2: String - private val result1: String - private val result2: String + val ignored1: String = ignored1.filterNot { it == '.' } + val ignored2: String = ignored2.filterNot { it == '.' } + val result1: String = result1.filterNot { it == '.' } + val result2: String = result2.filterNot { it == '.' } private var inner = true private var changedLines: IntPair? = null - init { - this.input1 = input1 - this.input2 = input2 - this.ignored1 = ignored1.filterNot { it == '.' } - this.ignored2 = ignored2.filterNot { it == '.' } - this.result1 = result1.filterNot { it == '.' } - this.result2 = result2.filterNot { it == '.' } - } - fun noInnerChanges(): Test { inner = false return this diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/SplitComparisonUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/SplitComparisonUtilTest.kt index 0e52c2c09115..e25ec85c1243 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/SplitComparisonUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/SplitComparisonUtilTest.kt @@ -74,6 +74,23 @@ class SplitComparisonUtilTest : ComparisonUtilTestBase() { default(del(0, 0, 1), mod(1, 0, 1, 1), del(2, 1, 1)) testAll() } + + splitter(trim = false) { + ("< i" - "" - "x'y'>") + (" " - " -- ").default() + testAll() + } + + lines_inner { + ("x'y'>" - "x'>") + (" -- " - " ").default() + testAll() + } } fun testWhitespaceOnlyChanges() { @@ -219,6 +252,12 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() { ("- -" - "- -").ignore() testIgnore() } + + words { + ("A_B_" - "X_") + ("--- " - "- ").default() + testAll() + } } fun testFixedBugs() { @@ -336,6 +375,26 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() { (" ---" - "--- ").default() testDefault() } + + lines_inner { + ("A B_C D" - "A_B C_D") + (" -- - " - " -- - ").default() + (" -- - " - " -- ").trim() + (" - " - " - ").ignore() + testAll() + } + + lines_inner { + ("B_C_D_" - "X_Y_Z_") + ("- - - " - "- - - ").default() + testAll() + } + + words { + ("!x_!_z" - "!_!_y z") + (" - " - " -- ").default() + testDefault() + } } fun `test trailing punctuation`() { diff --git a/platform/diff-impl/tests/com/intellij/diff/util/DiffUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/util/DiffUtilTest.kt index 538809266550..365e723690b8 100644 --- a/platform/diff-impl/tests/com/intellij/diff/util/DiffUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/util/DiffUtilTest.kt @@ -30,9 +30,11 @@ */ package com.intellij.diff.util +import com.intellij.diff.DiffRequestFactoryImpl import com.intellij.diff.DiffTestCase import com.intellij.openapi.diff.DiffBundle import com.intellij.util.containers.ContainerUtil +import java.io.File class DiffUtilTest : DiffTestCase() { fun `test getSortedIndexes`() { @@ -78,4 +80,50 @@ class DiffUtilTest : DiffTestCase() { doTest(2, 1, "There are 2 changes and one conflict left") doTest(2, 3, "There are 2 changes and 3 conflicts left") } + + fun `test diff content titles`() { + fun doTest(path: String, expected: String) { + val filePath = createFilePath(path) + val actual1 = DiffRequestFactoryImpl.getContentTitle(filePath) + val actual2 = DiffRequestFactoryImpl.getTitle(filePath, null, " <-> ") + val actual3 = DiffRequestFactoryImpl.getTitle(null, filePath, " <-> ") + + val expectedNative = expected.replace('/', File.separatorChar) + assertEquals(expectedNative, actual1) + assertEquals(expectedNative, actual2) + assertEquals(expectedNative, actual3) + } + + doTest("file.txt", "file.txt") + doTest("/path/to/file.txt", "file.txt (/path/to)") + doTest("/path/to/dir/", "/path/to/dir") + } + + fun `test diff request titles`() { + fun doTest(path1: String, path2: String, expected: String) { + val filePath1 = createFilePath(path1) + val filePath2 = createFilePath(path2) + val actual = DiffRequestFactoryImpl.getTitle(filePath1, filePath2, " <-> ") + assertEquals(expected.replace('/', File.separatorChar), actual) + } + + doTest("file1.txt", "file1.txt", "file1.txt") + doTest("/path/to/file1.txt", "/path/to/file1.txt", "file1.txt (/path/to)") + doTest("/path/to/dir1/", "/path/to/dir1/", "/path/to/dir1") + + doTest("file1.txt", "file2.txt", "file1.txt <-> file2.txt") + doTest("/path/to/file1.txt", "/path/to/file2.txt", "file1.txt <-> file2.txt (/path/to)") + doTest("/path/to/dir1/", "/path/to/dir2/", "dir1 <-> dir2 (/path/to)") + + doTest("/path/to/file1.txt", "/path/to_another/file1.txt", "file1.txt (/path/to <-> /path/to_another)") + doTest("/path/to/file1.txt", "/path/to_another/file2.txt", "file1.txt <-> file2.txt (/path/to <-> /path/to_another)") + doTest("/path/to/dir1/", "/path/to_another/dir2/", "dir1 <-> dir2 (/path/to <-> /path/to_another)") + + doTest("file1.txt", "/path/to/file1.txt", "file1.txt <-> /path/to/file1.txt") + doTest("file1.txt", "/path/to/file2.txt", "file1.txt <-> /path/to/file2.txt") + + doTest("/path/to/dir1/", "/path/to/file2.txt", "dir1/ <-> file2.txt (/path/to)") + doTest("/path/to/file1.txt", "/path/to/dir2/", "file1.txt <-> dir2/ (/path/to)") + doTest("/path/to/dir1/", "/path/to_another/file2.txt", "dir1/ <-> file2.txt (/path/to <-> /path/to_another)") + } } diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/ui/DvcsBundle.properties b/platform/dvcs-impl/src/com/intellij/dvcs/ui/DvcsBundle.properties index 5e671723de52..7848fefce156 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/ui/DvcsBundle.properties +++ b/platform/dvcs-impl/src/com/intellij/dvcs/ui/DvcsBundle.properties @@ -8,7 +8,7 @@ clone.parent.dir=&Parent Directory: clone.parent.missing.error=The parent path {0} must exist. clone.repository.url={0} Repository URL: clone.test.failed.error=Repository test has failed. -clone.test.success.message=Connection to repository {0} has been successful. +clone.test.success.message=Connection to {0} was established successfully. clone.test.connection.title=Test Connection clone.test=&Test clone.testing=Testing {0} diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/AntialiasingType.java b/platform/editor-ui-api/src/com/intellij/ide/ui/AntialiasingType.java index f14b7e408a53..3fda7fed307c 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/AntialiasingType.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/AntialiasingType.java @@ -16,8 +16,7 @@ package com.intellij.ide.ui; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.util.ui.UIUtil; -import sun.swing.SwingUtilities2; +import com.intellij.util.ui.GraphicsUtil; import java.awt.*; @@ -54,8 +53,8 @@ public enum AntialiasingType { isEnabled = enabled; } - public SwingUtilities2.AATextInfo getTextInfo() { - return !isEnabled ? null : new SwingUtilities2.AATextInfo(myHint, UIUtil.getLcdContrastValue()); + public Object getTextInfo() { + return isEnabled ? GraphicsUtil.createAATextInfo(myHint) : null; } @Override diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.kt b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.kt index 89a5b12e925a..08ed57c673c0 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.kt +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.kt @@ -19,6 +19,7 @@ import com.intellij.ide.WelcomeWizardUtil import com.intellij.openapi.Disposable import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.* +import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.util.IconLoader import com.intellij.openapi.util.Pair import com.intellij.openapi.util.SystemInfo @@ -49,7 +50,7 @@ class UISettings : BaseState(), PersistentStateComponent { // should be stored or shouldn't by the provided filter only. @get:Property(filter = FontFilter::class) @get:OptionTag("FONT_FACE") - var fontFace by storedProperty() + var fontFace by string() @get:Property(filter = FontFilter::class) @get:OptionTag("FONT_SIZE") @@ -264,6 +265,8 @@ class UISettings : BaseState(), PersistentStateComponent { } companion object { + private val LOG = Logger.getInstance(UISettings::class.java) + const val ANIMATION_DURATION = 300 // Milliseconds /** Not tabbed pane. */ @@ -369,14 +372,16 @@ class UISettings : BaseState(), PersistentStateComponent { @JvmStatic fun restoreFontSize(readSize: Int, readScale: Float?): Int { + var size = readSize if (readScale == null || readScale <= 0) { // Reset font to default on switch from IDE-managed HiDPI to JRE-managed HiDPI. Doesn't affect OSX. - if (UIUtil.isJreHiDPIEnabled() && !SystemInfo.isMac) return UIUtil.DEF_SYSTEM_FONT_SIZE.toInt() + if (UIUtil.isJreHiDPIEnabled() && !SystemInfo.isMac) size = UIUtil.DEF_SYSTEM_FONT_SIZE.toInt() } else { - return ((readSize.toFloat() / readScale) * normalizingScale).toInt() + size = ((readSize.toFloat() / readScale) * normalizingScale).toInt() } - return readSize + LOG.info("Loaded: fontSize=$readSize, fontScale=$readScale; restored: fontSize=$size, fontScale=$normalizingScale") + return size } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/importing/ImportSpec.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/importing/ImportSpec.java similarity index 100% rename from platform/external-system-impl/src/com/intellij/openapi/externalSystem/importing/ImportSpec.java rename to platform/external-system-api/src/com/intellij/openapi/externalSystem/importing/ImportSpec.java diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/importing/ImportSpecBuilder.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/importing/ImportSpecBuilder.java similarity index 98% rename from platform/external-system-impl/src/com/intellij/openapi/externalSystem/importing/ImportSpecBuilder.java rename to platform/external-system-api/src/com/intellij/openapi/externalSystem/importing/ImportSpecBuilder.java index 6b9ad4fd2c69..d548cdc0924e 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/importing/ImportSpecBuilder.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/importing/ImportSpecBuilder.java @@ -21,7 +21,7 @@ import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/importing/ImportSpecImpl.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/importing/ImportSpecImpl.java similarity index 100% rename from platform/external-system-impl/src/com/intellij/openapi/externalSystem/importing/ImportSpecImpl.java rename to platform/external-system-api/src/com/intellij/openapi/externalSystem/importing/ImportSpecImpl.java diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ProgressExecutionMode.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/execution/ProgressExecutionMode.java similarity index 100% rename from platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ProgressExecutionMode.java rename to platform/external-system-api/src/com/intellij/openapi/externalSystem/service/execution/ProgressExecutionMode.java diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ExternalProjectRefreshCallback.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/ExternalProjectRefreshCallback.java similarity index 100% rename from platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ExternalProjectRefreshCallback.java rename to platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/ExternalProjectRefreshCallback.java diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/ProjectDataManager.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/ProjectDataManager.java new file mode 100644 index 000000000000..52582de8366b --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/ProjectDataManager.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2017 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.externalSystem.service.project; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataService; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +/** + * Aggregates all {@link ProjectDataService#EP_NAME registered data services} + * and provides entry points for project data management. + * + * @author Vladislav Soroka + * @since 4/16/13 11:38 AM + */ +public interface ProjectDataManager { + static ProjectDataManager getInstance() { + return ServiceManager.getService(ProjectDataManager.class); + } + + @SuppressWarnings("unchecked") + void importData(@NotNull Collection> nodes, + @NotNull Project project, + @NotNull IdeModifiableModelsProvider modelsProvider, + boolean synchronous); + + void importData(@NotNull Collection> nodes, @NotNull Project project, boolean synchronous); + + void importData(@NotNull DataNode node, + @NotNull Project project, + @NotNull IdeModifiableModelsProvider modelsProvider, + boolean synchronous); + + void importData(@NotNull DataNode node, + @NotNull Project project, + boolean synchronous); + + void ensureTheDataIsReadyToUse(@Nullable DataNode dataNode); + + @Nullable + ExternalProjectInfo getExternalProjectData(@NotNull Project project, + @NotNull ProjectSystemId projectSystemId, + @NotNull String externalProjectPath); + + @NotNull + Collection getExternalProjectsData(@NotNull Project project, @NotNull ProjectSystemId projectSystemId); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManager.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManager.java new file mode 100644 index 000000000000..86a068b12e9b --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManager.java @@ -0,0 +1,45 @@ +/* + * 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.externalSystem.service.project.manage; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.externalSystem.importing.ImportSpec; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * @author Vladislav.Soroka + * @since 10/23/2014 + */ +public interface ExternalProjectsManager { + + static ExternalProjectsManager getInstance(@NotNull Project project) { + return ServiceManager.getService(project, ExternalProjectsManager.class); + } + + @NotNull + Project getProject(); + + void refreshProject(@NotNull String externalProjectPath, @NotNull ImportSpec importSpec); + + void runWhenInitialized(Runnable runnable); + + boolean isIgnored(@NotNull ProjectSystemId systemId, @NotNull String projectPath); + + void setIgnored(@NotNull DataNode dataNode, boolean isIgnored); +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenRemoteTask.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataImportListener.java similarity index 53% rename from plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenRemoteTask.java rename to platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataImportListener.java index 0585cf3caf74..0c08fbe5687d 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/remote/MavenRemoteTask.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataImportListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -13,19 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.maven.utils.library.remote; +package com.intellij.openapi.externalSystem.service.project.manage; -import com.intellij.openapi.progress.ProgressIndicator; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.intellij.util.messages.Topic; -public interface MavenRemoteTask { - @NotNull - Result execute(@NotNull Argument arg, ProgressIndicator indicator); +/** + * @author Vladislav Soroka + * @since 4/13/17 11:38 AM + */ +public interface ProjectDataImportListener { + Topic TOPIC = new Topic<>("project data import listener", ProjectDataImportListener.class); - String getName(@NotNull Argument arg); - - interface ResultProcessor { - void process(@Nullable Result result); - } + void onImportFinished(String projectPath); } diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemSettings.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemSettings.java index 280da73e6538..71255e518dfb 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemSettings.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemSettings.java @@ -16,6 +16,11 @@ package com.intellij.openapi.externalSystem.settings; import com.intellij.openapi.Disposable; +import com.intellij.openapi.externalSystem.ExternalSystemManager; +import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; import com.intellij.openapi.project.Project; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.messages.Topic; @@ -138,13 +143,17 @@ public abstract class AbstractExternalSystemSettings< } public void setLinkedProjectsSettings(@NotNull Collection settings) { + setLinkedProjectsSettings(settings, null); + } + + private void setLinkedProjectsSettings(@NotNull Collection settings, @Nullable ExternalSystemSettingsListener listener) { List added = ContainerUtilRt.newArrayList(); Map removed = ContainerUtilRt.newHashMap(myLinkedProjectsSettings); myLinkedProjectsSettings.clear(); for (PS current : settings) { myLinkedProjectsSettings.put(current.getExternalProjectPath(), current); } - + for (PS current : settings) { PS old = removed.remove(current.getExternalProjectPath()); if (old == null) { @@ -152,15 +161,24 @@ public abstract class AbstractExternalSystemSettings< } else { if (current.isUseAutoImport() != old.isUseAutoImport()) { + if (listener != null) { + listener.onUseAutoImportChange(current.isUseAutoImport(), current.getExternalProjectPath()); + } getPublisher().onUseAutoImportChange(current.isUseAutoImport(), current.getExternalProjectPath()); } checkSettings(old, current); } } if (!added.isEmpty()) { + if (listener != null) { + listener.onProjectsLinked(added); + } getPublisher().onProjectsLinked(added); } if (!removed.isEmpty()) { + if (listener != null) { + listener.onProjectsUnlinked(removed.keySet()); + } getPublisher().onProjectsUnlinked(removed.keySet()); } } @@ -192,10 +210,27 @@ public abstract class AbstractExternalSystemSettings< protected void loadState(@NotNull State state) { Set settings = state.getLinkedExternalProjectsSettings(); if (settings != null) { - myLinkedProjectsSettings.clear(); - for (PS projectSettings : settings) { - myLinkedProjectsSettings.put(projectSettings.getExternalProjectPath(), projectSettings); - } + setLinkedProjectsSettings(settings, new ExternalSystemSettingsListenerAdapter() { + @Override + public void onProjectsLinked(@NotNull Collection linked) { + for (Object o : linked) { + final ExternalProjectSettings settings = (ExternalProjectSettings)o; + for (ExternalSystemManager manager : ExternalSystemManager.EP_NAME.getExtensions()) { + AbstractExternalSystemSettings se = (AbstractExternalSystemSettings)manager.getSettingsProvider().fun(myProject); + ProjectSystemId externalSystemId = manager.getSystemId(); + if (settings == se.getLinkedProjectSettings(settings.getExternalProjectPath())) { + ExternalProjectsManager.getInstance(myProject).refreshProject( + settings.getExternalProjectPath(), + new ImportSpecBuilder(myProject, externalSystemId) + .useDefaultCallback() + .use(ProgressExecutionMode.IN_BACKGROUND_ASYNC) + .build() + ); + } + } + } + } + }); } } diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/ExternalProjectSettings.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/ExternalProjectSettings.java index ba97513e8a31..866848c1adab 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/ExternalProjectSettings.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/ExternalProjectSettings.java @@ -16,7 +16,6 @@ package com.intellij.openapi.externalSystem.settings; import com.intellij.openapi.util.Comparing; -import com.intellij.util.xmlb.annotations.AbstractCollection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,7 +36,7 @@ public abstract class ExternalProjectSettings implements Comparable getModules() { - return myModules == null ? Collections.emptySet() : myModules; + return myModules == null ? Collections.emptySet() : myModules; } public void setModules(@Nullable Set modules) { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/DetachExternalProjectAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/DetachExternalProjectAction.java index e84d1b09ca54..56ef19992f37 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/DetachExternalProjectAction.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/DetachExternalProjectAction.java @@ -18,20 +18,17 @@ package com.intellij.openapi.externalSystem.action; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.externalSystem.model.DataNode; import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.model.ProjectKeys; import com.intellij.openapi.externalSystem.model.ProjectSystemId; -import com.intellij.openapi.externalSystem.model.project.ModuleData; import com.intellij.openapi.externalSystem.model.project.ProjectData; -import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; import com.intellij.openapi.externalSystem.view.ProjectNode; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfoRt; import com.intellij.util.containers.ContainerUtilRt; @@ -87,7 +84,7 @@ public class DetachExternalProjectAction extends ExternalSystemNodeAction orphanModules = ContainerUtilRt.newArrayList(); @@ -102,8 +99,8 @@ public class DetachExternalProjectAction extends ExternalSystemNodeAction>emptyList(), projectData, project, false); + ProjectDataManagerImpl.getInstance().removeData( + ProjectKeys.MODULE, orphanModules, Collections.emptyList(), projectData, project, false); } } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemSelectProjectDataToImportAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemSelectProjectDataToImportAction.java index 0528ca44fe40..85e0fd2dfcc1 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemSelectProjectDataToImportAction.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemSelectProjectDataToImportAction.java @@ -20,7 +20,7 @@ import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.project.ProjectData; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager; import com.intellij.openapi.externalSystem.service.ui.ExternalProjectDataSelectorDialog; import com.intellij.openapi.externalSystem.view.ExternalSystemNode; import com.intellij.openapi.externalSystem.view.ProjectNode; diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/IgnoreExternalProjectAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/IgnoreExternalProjectAction.java index 5b057a8bad08..2581635886ed 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/IgnoreExternalProjectAction.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/IgnoreExternalProjectAction.java @@ -24,7 +24,7 @@ import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.project.ExternalConfigPathAware; import com.intellij.openapi.externalSystem.model.project.ProjectData; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; import com.intellij.openapi.externalSystem.view.ExternalSystemNode; diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/AssignShortcutAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/AssignShortcutAction.java index 0008a6016657..4a22db75eeb3 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/AssignShortcutAction.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/AssignShortcutAction.java @@ -24,7 +24,7 @@ import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.project.ModuleData; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.model.task.TaskData; -import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl; import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemKeymapExtension; import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemShortcutsManager; import com.intellij.openapi.externalSystem.view.ExternalSystemNode; @@ -55,7 +55,7 @@ public class AssignShortcutAction extends ExternalSystemNodeAction { @NotNull ProjectSystemId projectSystemId, @NotNull TaskData taskData, @NotNull AnActionEvent e) { - final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManager.getInstance(project).getShortcutsManager(); + final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManagerImpl.getInstance(project).getShortcutsManager(); final String actionId = shortcutsManager.getActionId(taskData.getLinkedExternalProjectPath(), taskData.getName()); if (actionId != null) { AnAction action = ActionManager.getInstance().getAction(actionId); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleTaskActivationAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleTaskActivationAction.java index 07b4bf54144e..eb575a58b73c 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleTaskActivationAction.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleTaskActivationAction.java @@ -22,7 +22,7 @@ import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; import com.intellij.openapi.externalSystem.model.task.TaskData; import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; -import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl; import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; import com.intellij.openapi.externalSystem.view.ExternalSystemNode; import com.intellij.openapi.externalSystem.view.RunConfigurationNode; @@ -108,6 +108,6 @@ public abstract class ToggleTaskActivationAction extends ExternalSystemToggleAct private ExternalSystemTaskActivator getTaskActivator(AnActionEvent e) { - return ExternalProjectsManager.getInstance(getProject(e)).getTaskActivator(); + return ExternalProjectsManagerImpl.getInstance(getProject(e)).getTaskActivator(); } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java index 6024f5d75af1..674e40369841 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java @@ -20,7 +20,7 @@ import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder; import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.service.project.ProjectRenameAware; -import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl; import com.intellij.openapi.externalSystem.service.ui.ExternalToolWindowManager; import com.intellij.openapi.externalSystem.service.vcs.ExternalSystemVcsRegistrar; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; @@ -62,7 +62,7 @@ public class ExternalSystemStartupActivity implements StartupActivity { ProjectRenameAware.beAware(project); }; - ExternalProjectsManager.getInstance(project).init(); + ExternalProjectsManagerImpl.getInstance(project).init(); DumbService.getInstance(project).runWhenSmart(DisposeAwareRunnable.create(task, project)); } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java index 7373448af253..7f35724caed1 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2017 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.externalSystem.service.execution; import com.intellij.diagnostic.logging.LogConfigurationPanel; @@ -40,6 +55,8 @@ import com.intellij.util.ExceptionUtil; import com.intellij.util.net.NetUtils; import com.intellij.util.text.CharArrayUtil; import com.intellij.util.text.DateFormatUtil; +import com.intellij.util.xmlb.Accessor; +import com.intellij.util.xmlb.SerializationFilter; import com.intellij.util.xmlb.XmlSerializer; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -53,8 +70,7 @@ import java.io.OutputStream; * @since 23.05.13 18:30 */ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase { - - private static final Logger LOG = Logger.getInstance("#" + ExternalSystemRunConfiguration.class.getName()); + private static final Logger LOG = Logger.getInstance(ExternalSystemRunConfiguration.class); private ExternalSystemTaskExecutionSettings mySettings = new ExternalSystemTaskExecutionSettings(); @@ -90,7 +106,20 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase { @Override public void writeExternal(Element element) throws WriteExternalException { super.writeExternal(element); - element.addContent(XmlSerializer.serialize(mySettings)); + element.addContent(XmlSerializer.serialize(mySettings, new SerializationFilter() { + @Override + public boolean accepts(@NotNull Accessor accessor, @NotNull Object bean) { + // only these fields due to backward compatibility + switch (accessor.getName()) { + case "passParentEnvs": + return !mySettings.isPassParentEnvs(); + case "env": + return !mySettings.getEnv().isEmpty(); + default: + return true; + } + } + })); } @NotNull diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/TaskCompletionProvider.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/TaskCompletionProvider.java index bb178343685a..1bcd738b7d87 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/TaskCompletionProvider.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/TaskCompletionProvider.java @@ -26,13 +26,12 @@ import com.intellij.openapi.externalSystem.model.project.ModuleData; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.model.task.TaskData; import com.intellij.openapi.externalSystem.service.execution.cmd.CommandLineCompletionProvider; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager; import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.TextAccessor; -import com.intellij.util.BooleanFunction; import com.intellij.util.containers.ContainerUtil; import groovyjarjarcommonscli.Options; import icons.ExternalSystemIcons; diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java index 817d01c69b3c..d6447c1e4619 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java @@ -1,6 +1,5 @@ package com.intellij.openapi.externalSystem.service.internal; -import com.intellij.execution.configurations.ParametersList; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.model.DataNode; @@ -15,7 +14,7 @@ import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskState; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType; import com.intellij.openapi.externalSystem.service.ExternalSystemFacadeManager; import com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl; import com.intellij.openapi.externalSystem.service.remote.ExternalSystemProgressNotificationManagerImpl; import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemProjectResolver; import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; @@ -139,7 +138,7 @@ public class ExternalSystemResolveProjectTask extends AbstractExternalSystemTask final long currentTimeMillis = System.currentTimeMillis(); projectInfo.setLastImportTimestamp(currentTimeMillis); projectInfo.setLastSuccessfulImportTimestamp(state == ExternalSystemTaskState.FAILED ? -1 : currentTimeMillis); - ProjectDataManager.getInstance().updateExternalProjectData(getIdeProject(), projectInfo); + ProjectDataManagerImpl.getInstance().updateExternalProjectData(getIdeProject(), projectInfo); } } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/notification/ExternalSystemNotificationManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/notification/ExternalSystemNotificationManager.java index 0a18419b8b9e..0b811f1f0f11 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/notification/ExternalSystemNotificationManager.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/notification/ExternalSystemNotificationManager.java @@ -28,7 +28,7 @@ import com.intellij.openapi.externalSystem.ExternalSystemConfigurableAware; import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.model.LocationAwareExternalSystemException; import com.intellij.openapi.externalSystem.model.ProjectSystemId; -import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; @@ -51,6 +51,7 @@ import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentFactory; import com.intellij.ui.content.MessageView; import com.intellij.util.ObjectUtils; +import com.intellij.util.SmartList; import com.intellij.util.concurrency.SequentialTaskExecutor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; @@ -58,6 +59,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; @@ -79,12 +82,14 @@ public class ExternalSystemNotificationManager implements Disposable { @NotNull private final Project myProject; @NotNull private final Set myNotifications; + @NotNull private final Map myUniqueNotifications; @NotNull private final Set initializedExternalSystem; @NotNull private final MessageCounter myMessageCounter; public ExternalSystemNotificationManager(@NotNull final Project project) { myProject = project; myNotifications = ContainerUtil.newConcurrentSet(); + myUniqueNotifications = ContainerUtil.newConcurrentMap(); initializedExternalSystem = ContainerUtil.newConcurrentSet(); myMessageCounter = new MessageCounter(); } @@ -139,46 +144,66 @@ public class ExternalSystemNotificationManager implements Disposable { showNotification(externalSystemId, notificationData); } + public boolean isNotificationActive(@NotNull Key notificationKey) { + Notification notification = myUniqueNotifications.get(notificationKey); + return notification != null && !notification.isExpired(); + } + public void showNotification(@NotNull final ProjectSystemId externalSystemId, @NotNull final NotificationData notificationData) { + showNotification(externalSystemId, notificationData, null); + } + + public void showNotification(@NotNull final ProjectSystemId externalSystemId, + @NotNull final NotificationData notificationData, + @Nullable Key notificationKey) { + if (notificationKey != null && isNotificationActive(notificationKey)) return; myUpdater.submit(() -> { if (myProject.isDisposed()) return; final Application app = ApplicationManager.getApplication(); - Runnable action = () -> { - if (!initializedExternalSystem.contains(externalSystemId)) { - app.runWriteAction(() -> { - if (myProject.isDisposed()) return; - ExternalSystemUtil.ensureToolWindowContentInitialized(myProject, externalSystemId); - initializedExternalSystem.add(externalSystemId); - }); - } - if (myProject.isDisposed()) return; - NotificationGroup group; - if (notificationData.getBalloonGroup() == null) { - ExternalProjectsView externalProjectsView = - ExternalProjectsManager.getInstance(myProject).getExternalProjectsView(externalSystemId); - group = externalProjectsView instanceof ExternalProjectsViewImpl ? - ((ExternalProjectsViewImpl)externalProjectsView).getNotificationGroup() : null; - } - else { - final NotificationGroup registeredGroup = NotificationGroup.findRegisteredGroup(notificationData.getBalloonGroup()); - group = registeredGroup != null ? registeredGroup : NotificationGroup.balloonGroup(notificationData.getBalloonGroup()); - } - if (group == null) return; + Runnable action = () -> { + if (!initializedExternalSystem.contains(externalSystemId)) { + app.runWriteAction(() -> { + if (myProject.isDisposed()) return; + ExternalSystemUtil.ensureToolWindowContentInitialized(myProject, externalSystemId); + initializedExternalSystem.add(externalSystemId); + }); + } + if (myProject.isDisposed()) return; + NotificationGroup group; + if (notificationData.getBalloonGroup() == null) { + ExternalProjectsView externalProjectsView = + ExternalProjectsManagerImpl.getInstance(myProject).getExternalProjectsView(externalSystemId); + group = externalProjectsView instanceof ExternalProjectsViewImpl ? + ((ExternalProjectsViewImpl)externalProjectsView).getNotificationGroup() : null; + } + else { + final NotificationGroup registeredGroup = NotificationGroup.findRegisteredGroup(notificationData.getBalloonGroup()); + group = registeredGroup != null ? registeredGroup : NotificationGroup.balloonGroup(notificationData.getBalloonGroup()); + } + if (group == null) return; - final Notification notification = group.createNotification( - notificationData.getTitle(), notificationData.getMessage(), - notificationData.getNotificationCategory().getNotificationType(), notificationData.getListener()); + final Notification notification = group.createNotification( + notificationData.getTitle(), notificationData.getMessage(), + notificationData.getNotificationCategory().getNotificationType(), notificationData.getListener()); + if (notificationKey == null) { myNotifications.add(notification); + } + else { + Notification oldNotification = myUniqueNotifications.put(notificationKey, notification); + if (oldNotification != null) { + oldNotification.expire(); + } + } - if (notificationData.isBalloonNotification()) { - applyNotification(notification); - } - else { - addMessage(notification, externalSystemId, notificationData); - } - }; + if (notificationData.isBalloonNotification()) { + applyNotification(notification); + } + else { + addMessage(notification, externalSystemId, notificationData); + } + }; app.invokeLater(action, ModalityState.defaultModalityState(), myProject.getDisposed()); }); } @@ -206,6 +231,15 @@ public class ExternalSystemNotificationManager implements Disposable { } } + List toRemove = new SmartList<>(); + myUniqueNotifications.forEach((key, notification) -> { + if (groupName == null || groupName.equals(notification.getGroupId())) { + notification.expire(); + toRemove.add(key); + } + }); + toRemove.forEach(myUniqueNotifications::remove); + final ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.MESSAGES_WINDOW); if (toolWindow == null) return; @@ -376,6 +410,7 @@ public class ExternalSystemNotificationManager implements Disposable { @Override public void dispose() { myNotifications.clear(); + myUniqueNotifications.clear(); initializedExternalSystem.clear(); } } \ No newline at end of file diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/autoimport/ExternalSystemProjectsWatcher.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/autoimport/ExternalSystemProjectsWatcher.java index bb8b2db75726..ce2429871012 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/autoimport/ExternalSystemProjectsWatcher.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/autoimport/ExternalSystemProjectsWatcher.java @@ -33,7 +33,7 @@ import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMo import com.intellij.openapi.externalSystem.service.internal.ExternalSystemProcessingManager; import com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager; import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager; import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; @@ -609,22 +609,20 @@ public class ExternalSystemProjectsWatcher extends ExternalSystemTaskNotificatio PsiFile psiFile = PsiManager.getInstance(myProject).findFile(file); if (psiFile != null) { final CRC32 crc32 = new CRC32(); - ApplicationManager.getApplication().runReadAction(() -> { - psiFile.acceptChildren(new PsiRecursiveElementVisitor() { - @Override - public void visitElement(PsiElement element) { - if (element instanceof LeafElement && !(element instanceof PsiWhiteSpace) && !(element instanceof PsiComment)) { - String text = element.getText(); - if (!text.trim().isEmpty()) { - for (int i = 0, end = text.length(); i < end; i++) { - crc32.update(text.charAt(i)); - } + ApplicationManager.getApplication().runReadAction(() -> psiFile.acceptChildren(new PsiRecursiveElementVisitor() { + @Override + public void visitElement(PsiElement element) { + if (element instanceof LeafElement && !(element instanceof PsiWhiteSpace) && !(element instanceof PsiComment)) { + String text = element.getText(); + if (!text.trim().isEmpty()) { + for (int i = 0, end = text.length(); i < end; i++) { + crc32.update(text.charAt(i)); } } - super.visitElement(element); } - }); - }); + super.visitElement(element); + } + })); newCrc = crc32.getValue(); } else { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalModuleStructureExtension.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalModuleStructureExtension.java index 2d76753ee28b..c624421e1c8e 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalModuleStructureExtension.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalModuleStructureExtension.java @@ -176,6 +176,6 @@ public class ExternalModuleStructureExtension extends ModuleStructureExtension { private static void unlinkProject(@NotNull Project project, ProjectSystemId systemId, String rootProjectPath) { ExternalSystemApiUtil.getLocalSettings(project, systemId).forgetExternalProjects(Collections.singleton(rootProjectPath)); ExternalSystemApiUtil.getSettings(project, systemId).unlinkExternalProject(rootProjectPath); - ExternalProjectsManager.getInstance(project).forgetExternalProjectData(systemId, rootProjectPath); + ExternalProjectsManagerImpl.getInstance(project).forgetExternalProjectData(systemId, rootProjectPath); } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsDataStorage.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsDataStorage.java index de4e72d3f9e6..cc7d901fdaa8 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsDataStorage.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsDataStorage.java @@ -19,7 +19,10 @@ import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.ExternalSystemManager; -import com.intellij.openapi.externalSystem.model.*; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; +import com.intellij.openapi.externalSystem.model.Key; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo; import com.intellij.openapi.externalSystem.model.internal.InternalExternalProjectInfo; import com.intellij.openapi.externalSystem.model.project.ExternalConfigPathAware; @@ -35,7 +38,8 @@ import com.intellij.openapi.module.ModuleTypeId; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.util.*; +import com.intellij.util.Alarm; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import com.intellij.util.xmlb.annotations.AbstractCollection; @@ -105,7 +109,7 @@ public class ExternalProjectsDataStorage implements SettingsSavingComponent, Per final DataNode projectStructure = externalProjectInfo.getExternalProjectStructure(); if (projectStructure == null) return false; - ProjectDataManager.getInstance().ensureTheDataIsReadyToUse(projectStructure); + ProjectDataManagerImpl.getInstance().ensureTheDataIsReadyToUse(projectStructure); return externalProjectInfo.getExternalProjectPath().equals(projectStructure.getData().getLinkedExternalProjectPath()); } catch (Exception e) { @@ -262,7 +266,7 @@ public class ExternalProjectsDataStorage implements SettingsSavingComponent, Per if (linkedProjectSettings != null && ContainerUtil.isEmpty(linkedProjectSettings.getModules())) { final Set modulePaths = ContainerUtil.map2Set( - ExternalSystemApiUtil.findAllRecursively(externalProjectInfo.getExternalProjectStructure(), ProjectKeys.MODULE), + ExternalSystemApiUtil.findAllRecursively(externalProjectInfo.getExternalProjectStructure(), MODULE), node -> node.getData().getLinkedExternalProjectPath()); linkedProjectSettings.setModules(modulePaths); } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManagerImpl.java similarity index 92% rename from platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManager.java rename to platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManagerImpl.java index aea2cfc34737..e7dbc98ef102 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManager.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManagerImpl.java @@ -20,6 +20,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.ExternalSystemManager; +import com.intellij.openapi.externalSystem.importing.ImportSpec; import com.intellij.openapi.externalSystem.model.DataNode; import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; import com.intellij.openapi.externalSystem.model.ProjectSystemId; @@ -54,7 +55,7 @@ import static com.intellij.openapi.externalSystem.model.ProjectKeys.TASK; * @since 10/23/2014 */ @State(name = "ExternalProjectsManager", storages = {@Storage(StoragePathMacros.WORKSPACE_FILE)}) -public class ExternalProjectsManager implements PersistentStateComponent, Disposable { +public class ExternalProjectsManagerImpl implements ExternalProjectsManager, PersistentStateComponent, Disposable { private static final Logger LOG = Logger.getInstance(ExternalProjectsManager.class); private final AtomicBoolean isInitializationFinished = new AtomicBoolean(); @@ -71,12 +72,7 @@ public class ExternalProjectsManager implements PersistentStateComponent myProjectsViews = new SmartList<>(); private ExternalSystemProjectsWatcher myWatcher; - - public static ExternalProjectsManager getInstance(@NotNull Project project) { - return ServiceManager.getService(project, ExternalProjectsManager.class); - } - - public ExternalProjectsManager(@NotNull Project project) { + public ExternalProjectsManagerImpl(@NotNull Project project) { myProject = project; myShortcutsManager = new ExternalSystemShortcutsManager(project); Disposer.register(this, myShortcutsManager); @@ -84,7 +80,13 @@ public class ExternalProjectsManager implements PersistentStateComponent o.getSystemId().getId(), o -> o.getSystemId())); for (Map.Entry systemState : myState.getExternalSystemsState().entrySet()) { ProjectSystemId systemId = systemIds.get(systemState.getKey()); - if(systemId == null) continue; + if (systemId == null) continue; for (Map.Entry activationStateEntry : systemState.getValue().getExternalSystemsTaskActivation() .entrySet()) { @@ -243,6 +251,7 @@ public class ExternalProjectsManager implements PersistentStateComponent dataNode, boolean isIgnored) { ExternalProjectsDataStorage.getInstance(myProject).setIgnored(dataNode, isIgnored); ExternalSystemKeymapExtension.updateActions(myProject, ExternalSystemApiUtil.findAllRecursively(dataNode, TASK)); @@ -264,7 +274,7 @@ public class ExternalProjectsManager implements PersistentStateComponent projectToActionsMapping = MultiMap.create(); for (ExternalSystemManager manager : ExternalSystemApiUtil.getAllManagers()) { - projectToActionsMapping.putValues(manager.getSystemId(), ContainerUtil.emptyList()); + projectToActionsMapping.putValues(manager.getSystemId(), ContainerUtil.emptyList()); } ActionManager actionManager = ActionManager.getInstance(); @@ -194,7 +194,7 @@ public class ExternalSystemKeymapExtension implements KeymapExtension { private static void createActions(Project project, Collection> taskNodes) { ActionManager actionManager = ActionManager.getInstance(); - final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManager.getInstance(project).getShortcutsManager(); + final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManagerImpl.getInstance(project).getShortcutsManager(); if (actionManager != null) { for (DataNode each : taskNodes) { final DataNode moduleData = ExternalSystemApiUtil.findParent(each, ProjectKeys.MODULE); @@ -233,7 +233,7 @@ public class ExternalSystemKeymapExtension implements KeymapExtension { } public static String getActionPrefix(@NotNull Project project, @Nullable String path) { - return ExternalProjectsManager.getInstance(project).getShortcutsManager().getActionId(path, null); + return ExternalProjectsManagerImpl.getInstance(project).getShortcutsManager().getActionId(path, null); } public static void updateRunConfigurationActions(Project project, ProjectSystemId systemId) { @@ -251,7 +251,7 @@ public class ExternalSystemKeymapExtension implements KeymapExtension { Set settings = new THashSet<>( RunManager.getInstance(project).getConfigurationSettingsList(configurationType)); - final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManager.getInstance(project).getShortcutsManager(); + final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManagerImpl.getInstance(project).getShortcutsManager(); for (RunnerAndConfigurationSettings configurationSettings : settings) { ExternalSystemRunConfigurationAction runConfigurationAction = new ExternalSystemRunConfigurationAction(project, configurationSettings); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemRunManagerListener.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemRunManagerListener.java index 0426ef1f3a11..9df90b449f0f 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemRunManagerListener.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemRunManagerListener.java @@ -23,6 +23,7 @@ import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemTaskConfigurationType; import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl.ExternalProjectsStateProvider; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; import com.intellij.openapi.util.Pair; @@ -42,11 +43,11 @@ import static com.intellij.openapi.externalSystem.service.project.manage.Externa */ class ExternalSystemRunManagerListener implements RunManagerListener { - private ExternalProjectsManager myManager; + private ExternalProjectsManagerImpl myManager; private final Map> myMap; public ExternalSystemRunManagerListener(ExternalProjectsManager manager) { - myManager = manager; + myManager = (ExternalProjectsManagerImpl)manager; myMap = ContainerUtil.newConcurrentMap(); } @@ -61,7 +62,7 @@ class ExternalSystemRunManagerListener implements RunManagerListener { final Pair pair = myMap.remove(System.identityHashCode(settings)); if (pair == null) return; - final ExternalProjectsManager.ExternalProjectsStateProvider stateProvider = myManager.getStateProvider(); + final ExternalProjectsStateProvider stateProvider = myManager.getStateProvider(); final ExternalSystemTaskExecutionSettings taskExecutionSettings = ((ExternalSystemRunConfiguration)settings.getConfiguration()).getSettings(); @@ -87,7 +88,7 @@ class ExternalSystemRunManagerListener implements RunManagerListener { if (settings.getConfiguration() instanceof ExternalSystemRunConfiguration) { final Pair pair = myMap.get(System.identityHashCode(settings)); if (pair != null) { - final ExternalProjectsManager.ExternalProjectsStateProvider stateProvider = myManager.getStateProvider(); + final ExternalProjectsStateProvider stateProvider = myManager.getStateProvider(); final ExternalSystemTaskExecutionSettings taskExecutionSettings = ((ExternalSystemRunConfiguration)settings.getConfiguration()).getSettings(); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemTaskActivator.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemTaskActivator.java index 90cb58ce357d..44a507be9742 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemTaskActivator.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemTaskActivator.java @@ -29,20 +29,18 @@ import com.intellij.openapi.externalSystem.model.task.TaskData; import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemTaskConfigurationType; import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; -import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager.ExternalProjectsStateProvider; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl.ExternalProjectsStateProvider; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; import com.intellij.openapi.externalSystem.task.TaskCallback; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; -import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; -import com.intellij.util.Function; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.FactoryMap; @@ -96,7 +94,7 @@ public class ExternalSystemTaskActivator { public String getDescription(ProjectSystemId systemId, String projectPath, String taskName) { List result = new ArrayList<>(); final ExternalProjectsStateProvider stateProvider = - ExternalProjectsManager.getInstance(myProject).getStateProvider(); + ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider(); final TaskActivationState taskActivationState = stateProvider.getTasksActivation(systemId, projectPath); if (taskActivationState == null) return null; @@ -133,7 +131,8 @@ public class ExternalSystemTaskActivator { } public boolean runTasks(@NotNull Collection modules, @NotNull Phase... phases) { - final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider(); + final ExternalProjectsStateProvider stateProvider = + ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider(); final Queue> tasksQueue = new LinkedList<>(); @@ -245,7 +244,7 @@ public class ExternalSystemTaskActivator { } public boolean isTaskOfPhase(@NotNull TaskData taskData, @NotNull Phase phase) { - final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider(); + final ExternalProjectsStateProvider stateProvider = ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider(); final TaskActivationState taskActivationState = stateProvider.getTasksActivation(taskData.getOwner(), taskData.getLinkedExternalProjectPath()); if (taskActivationState == null) return false; @@ -263,7 +262,7 @@ public class ExternalSystemTaskActivator { public void addTasks(@NotNull Collection entries) { if (entries.isEmpty()) return; - final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider(); + final ExternalProjectsStateProvider stateProvider = ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider(); for (TaskActivationEntry entry : entries) { final TaskActivationState taskActivationState = stateProvider.getTasksActivation(entry.systemId, entry.projectPath); taskActivationState.getTasks(entry.phase).add(entry.taskName); @@ -279,7 +278,7 @@ public class ExternalSystemTaskActivator { public void removeTasks(@NotNull Collection entries) { if (entries.isEmpty()) return; - final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider(); + final ExternalProjectsStateProvider stateProvider = ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider(); for (TaskActivationEntry activationEntry : entries) { final TaskActivationState taskActivationState = stateProvider.getTasksActivation(activationEntry.systemId, activationEntry.projectPath); @@ -300,7 +299,7 @@ public class ExternalSystemTaskActivator { public void moveTasks(@NotNull Collection entries, int increment) { LOG.assertTrue(increment == -1 || increment == 1); - final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider(); + final ExternalProjectsStateProvider stateProvider = ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider(); for (TaskActivationEntry activationEntry : entries) { final TaskActivationState taskActivationState = stateProvider.getTasksActivation(activationEntry.systemId, activationEntry.projectPath); @@ -319,7 +318,7 @@ public class ExternalSystemTaskActivator { int increment) { LOG.assertTrue(increment == -1 || increment == 1); - final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider(); + final ExternalProjectsStateProvider stateProvider = ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider(); final Map activationMap = stateProvider.getProjectsTasksActivationMap(systemId); final List currentPaths = ContainerUtil.newArrayList(activationMap.keySet()); if (pathsGroup != null) { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java index bdb4445ef521..37fc4f8f27aa 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2017 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,394 +15,102 @@ */ package com.intellij.openapi.externalSystem.service.project.manage; -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.externalSystem.model.*; -import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; +import com.intellij.openapi.externalSystem.model.Key; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider; -import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl; -import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange; -import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; -import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; -import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.impl.ProjectImpl; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.NotNullLazyValue; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.Consumer; -import com.intellij.util.ExceptionUtil; -import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.ContainerUtilRt; -import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; - -import static com.intellij.util.containers.ContainerUtil.map2Array; +import java.util.Collection; /** - * Aggregates all {@link ProjectDataService#EP_NAME registered data services} and provides entry points for project data management. - * - * @author Denis Zhdanov - * @since 4/16/13 11:38 AM + * @deprecated use {@link com.intellij.openapi.externalSystem.service.project.ProjectDataManager} instead */ -public class ProjectDataManager { - - private static final Logger LOG = Logger.getInstance("#" + ProjectDataManager.class.getName()); - private static final com.intellij.openapi.util.Key DATA_READY = - com.intellij.openapi.util.Key.create("externalSystem.data.ready"); - - @NotNull private final NotNullLazyValue, List>>> myServices; +public class ProjectDataManager extends ProjectDataManagerImpl { public static ProjectDataManager getInstance() { - return ServiceManager.getService(ProjectDataManager.class); + return new ProjectDataManager(ProjectDataManagerImpl.getInstance()); } - public ProjectDataManager() { - myServices = new NotNullLazyValue, List>>>() { - @NotNull - @Override - protected Map, List>> compute() { - Map, List>> result = ContainerUtilRt.newHashMap(); - for (ProjectDataService service : ProjectDataService.EP_NAME.getExtensions()) { - List> services = result.get(service.getTargetDataKey()); - if (services == null) { - result.put(service.getTargetDataKey(), services = ContainerUtilRt.newArrayList()); - } - services.add(service); - } + private final ProjectDataManagerImpl delegate; - for (List> services : result.values()) { - ExternalSystemApiUtil.orderAwareSort(services); - } - return result; - } - }; - } + public ProjectDataManager(ProjectDataManagerImpl delegate) {this.delegate = delegate;} - @SuppressWarnings("unchecked") + @Override public void importData(@NotNull Collection> nodes, @NotNull Project project, @NotNull IdeModifiableModelsProvider modelsProvider, boolean synchronous) { - if (project.isDisposed()) return; - - MultiMap, DataNode> grouped = ExternalSystemApiUtil.recursiveGroup(nodes); - for (Key key : myServices.getValue().keySet()) { - if (!grouped.containsKey(key)) { - grouped.put(key, Collections.>emptyList()); - } - } - - final Collection> projects = grouped.get(ProjectKeys.PROJECT); - // only one project(can be multi-module project) expected for per single import - assert projects.size() == 1 || projects.isEmpty(); - - final DataNode projectNode = (DataNode)ContainerUtil.getFirstItem(projects); - final ProjectData projectData; - ProjectSystemId projectSystemId; - if (projectNode != null) { - projectData = projectNode.getData(); - projectSystemId = projectNode.getData().getOwner(); - ExternalProjectsDataStorage.getInstance(project).saveInclusionSettings(projectNode); - } - else { - projectData = null; - DataNode aModuleNode = (DataNode)ContainerUtil.getFirstItem(grouped.get(ProjectKeys.MODULE)); - projectSystemId = aModuleNode != null ? aModuleNode.getData().getOwner() : null; - } - - if (projectSystemId != null) { - ExternalSystemUtil.scheduleExternalViewStructureUpdate(project, projectSystemId); - } - - List onSuccessImportTasks = ContainerUtil.newSmartList(); - try { - final Set, Collection>>> entries = grouped.entrySet(); - final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); - if (indicator != null) { - indicator.setIndeterminate(false); - } - final int size = entries.size(); - int count = 0; - List postImportTasks = ContainerUtil.newSmartList(); - for (Map.Entry, Collection>> entry : entries) { - if (indicator != null) { - String message = ExternalSystemBundle.message( - "progress.update.text", projectSystemId != null ? projectSystemId.getReadableName() : "", - "Refresh " + getReadableText(entry.getKey())); - indicator.setText(message); - indicator.setFraction((double)count++ / size); - } - doImportData(entry.getKey(), entry.getValue(), projectData, project, modelsProvider, postImportTasks, onSuccessImportTasks); - } - - for (Runnable postImportTask : postImportTasks) { - postImportTask.run(); - } - - commit(modelsProvider, project, synchronous, "Imported data"); - if (indicator != null) { - indicator.setIndeterminate(true); - } - } - catch (Throwable t) { - dispose(modelsProvider, project, synchronous); - ExceptionUtil.rethrowAllAsUnchecked(t); - } - - for (Runnable onSuccessImportTask : ContainerUtil.reverse(onSuccessImportTasks)) { - onSuccessImportTask.run(); - } + delegate.importData(nodes, project, modelsProvider, synchronous); } - @NotNull - private static String getReadableText(@NotNull Key key) { - StringBuilder buffer = new StringBuilder(); - String s = key.toString(); - for (int i = 0; i < s.length(); i++) { - char currChar = s.charAt(i); - if (Character.isUpperCase(currChar)) { - if (i != 0) { - buffer.append(' '); - } - buffer.append(StringUtil.toLowerCase(currChar)); - } - else { - buffer.append(currChar); - } - } - return buffer.toString(); - } - - public void importData(@NotNull Collection> nodes, @NotNull Project project, boolean synchronous) { - Collection> dummy = ContainerUtil.newSmartList(); - for (DataNode node : nodes) { - dummy.add(node); - } - importData(dummy, project, new IdeModifiableModelsProviderImpl(project), synchronous); + @Override + public void importData(@NotNull Collection> nodes, + @NotNull Project project, boolean synchronous) { + delegate.importData(nodes, project, synchronous); } + @Override public void importData(@NotNull DataNode node, @NotNull Project project, @NotNull IdeModifiableModelsProvider modelsProvider, boolean synchronous) { - Collection> dummy = ContainerUtil.newSmartList(); - dummy.add(node); - importData(dummy, project, modelsProvider, synchronous); + delegate.importData(node, project, modelsProvider, synchronous); } + @Override public void importData(@NotNull DataNode node, - @NotNull Project project, - boolean synchronous) { - importData(node, project, new IdeModifiableModelsProviderImpl(project), synchronous); - } - - @SuppressWarnings("unchecked") - private void doImportData(@NotNull Key key, - @NotNull Collection> nodes, - @Nullable final ProjectData projectData, - @NotNull final Project project, - @NotNull final IdeModifiableModelsProvider modelsProvider, - @NotNull final List postImportTasks, - @NotNull final List onSuccessImportTasks) { - if (project.isDisposed()) return; - if (project instanceof ProjectImpl) { - assert ((ProjectImpl)project).isComponentsCreated(); - } - - final List> toImport = ContainerUtil.newSmartList(); - final List> toIgnore = ContainerUtil.newSmartList(); - - for (DataNode node : nodes) { - if (!key.equals(node.getKey())) continue; - - if (node.isIgnored()) { - toIgnore.add(node); - } - else { - toImport.add(node); - } - } - - ensureTheDataIsReadyToUse((Collection)toImport); - - final List> services = myServices.getValue().get(key); - if (services == null) { - LOG.warn(String.format( - "Can't import data nodes '%s'. Reason: no service is registered for key %s. Available services for %s", - toImport, key, myServices.getValue().keySet() - )); - } - else { - for (ProjectDataService service : services) { - final long importStartTime = System.currentTimeMillis(); - ((ProjectDataService)service).importData(toImport, projectData, project, modelsProvider); - if(LOG.isDebugEnabled()) { - final long importTimeInMs = (System.currentTimeMillis() - importStartTime); - LOG.debug(String.format("Service %s imported data in %d ms", service.getClass().getSimpleName(), importTimeInMs)); - } - - if(projectData != null) { - ensureTheDataIsReadyToUse((Collection)toIgnore); - final long removeStartTime = System.currentTimeMillis(); - final Computable> orphanIdeDataComputable = - ((ProjectDataService)service).computeOrphanData(toImport, projectData, project, modelsProvider); - ((ProjectDataService)service).removeData(orphanIdeDataComputable, toIgnore, projectData, project, modelsProvider); - if(LOG.isDebugEnabled()) { - final long removeTimeInMs = (System.currentTimeMillis() - removeStartTime); - LOG.debug(String.format("Service %s computed and removed data in %d ms", service.getClass().getSimpleName(), removeTimeInMs)); - } - } - } - } - - if (services != null && projectData != null) { - postImportTasks.add(() -> { - for (ProjectDataService service : services) { - if (service instanceof AbstractProjectDataService) { - final long taskStartTime = System.currentTimeMillis(); - ((AbstractProjectDataService)service).postProcess(toImport, projectData, project, modelsProvider); - if(LOG.isDebugEnabled()) { - final long taskTimeInMs = (System.currentTimeMillis() - taskStartTime); - LOG.debug(String.format("Service %s run post import task in %d ms", service.getClass().getSimpleName(), taskTimeInMs)); - } - } - } - }); - onSuccessImportTasks.add(() -> { - for (ProjectDataService service : services) { - if (service instanceof AbstractProjectDataService) { - final long taskStartTime = System.currentTimeMillis(); - ((AbstractProjectDataService)service).onSuccessImport(project); - if(LOG.isDebugEnabled()) { - final long taskTimeInMs = (System.currentTimeMillis() - taskStartTime); - LOG.debug(String.format("Service %s run post import task in %d ms", service.getClass().getSimpleName(), taskTimeInMs)); - } - } - } - }); - } + @NotNull Project project, boolean synchronous) { + delegate.importData(node, project, synchronous); } + @Override public void ensureTheDataIsReadyToUse(@Nullable DataNode dataNode) { - if (dataNode == null) return; - if (Boolean.TRUE.equals(dataNode.getUserData(DATA_READY))) return; - - ExternalSystemApiUtil.visit(dataNode, dataNode1 -> { - prepareDataToUse(dataNode1); - dataNode1.putUserData(DATA_READY, Boolean.TRUE); - }); + delegate.ensureTheDataIsReadyToUse(dataNode); } - @SuppressWarnings("unchecked") + @Override public void removeData(@NotNull Key key, @NotNull Collection toRemove, - @NotNull final Collection> toIgnore, - @NotNull final ProjectData projectData, + @NotNull Collection> toIgnore, + @NotNull ProjectData projectData, @NotNull Project project, - @NotNull final IdeModifiableModelsProvider modelsProvider, + @NotNull IdeModifiableModelsProvider modelsProvider, boolean synchronous) { - try { - List> services = myServices.getValue().get(key); - for (ProjectDataService service : services) { - final long removeStartTime = System.currentTimeMillis(); - service.removeData(new Computable.PredefinedValueComputable(toRemove), toIgnore, projectData, project, modelsProvider); - if(LOG.isDebugEnabled()) { - final long removeTimeInMs = System.currentTimeMillis() - removeStartTime; - LOG.debug(String.format("Service %s removed data in %d ms", service.getClass().getSimpleName(), removeTimeInMs)); - } - } - - commit(modelsProvider, project, synchronous, "Removed data"); - } - catch (Throwable t) { - dispose(modelsProvider, project, synchronous); - ExceptionUtil.rethrowAllAsUnchecked(t); - } + delegate.removeData(key, toRemove, toIgnore, projectData, project, modelsProvider, synchronous); } + @Override public void removeData(@NotNull Key key, @NotNull Collection toRemove, - @NotNull final Collection> toIgnore, - @NotNull final ProjectData projectData, - @NotNull Project project, - boolean synchronous) { - removeData(key, toRemove, toIgnore, projectData, project, new IdeModifiableModelsProviderImpl(project), synchronous); + @NotNull Collection> toIgnore, + @NotNull ProjectData projectData, + @NotNull Project project, boolean synchronous) { + delegate.removeData(key, toRemove, toIgnore, projectData, project, synchronous); } - public void updateExternalProjectData(@NotNull Project project, @NotNull ExternalProjectInfo externalProjectInfo) { - if (!project.isDisposed()) { - ExternalProjectsManager.getInstance(project).updateExternalProjectData(externalProjectInfo); - } + @Override + public void updateExternalProjectData(@NotNull Project project, + @NotNull ExternalProjectInfo externalProjectInfo) { + delegate.updateExternalProjectData(project, externalProjectInfo); } @Nullable + @Override public ExternalProjectInfo getExternalProjectData(@NotNull Project project, @NotNull ProjectSystemId projectSystemId, @NotNull String externalProjectPath) { - return !project.isDisposed() ? ExternalProjectsDataStorage.getInstance(project).get(projectSystemId, externalProjectPath) : null; + return delegate.getExternalProjectData(project, projectSystemId, externalProjectPath); } @NotNull - public Collection getExternalProjectsData(@NotNull Project project, @NotNull ProjectSystemId projectSystemId) { - if (!project.isDisposed()) { - return ExternalProjectsDataStorage.getInstance(project).list(projectSystemId); - } - else { - return ContainerUtil.emptyList(); - } - } - - private void ensureTheDataIsReadyToUse(@NotNull Collection> nodes) { - for (DataNode node : nodes) { - ensureTheDataIsReadyToUse(node); - } - } - - private void prepareDataToUse(@NotNull DataNode dataNode) { - final Map, List>> servicesByKey = myServices.getValue(); - List> services = servicesByKey.get(dataNode.getKey()); - if (services != null) { - try { - dataNode.prepareData(map2Array(services, ClassLoader.class, service -> service.getClass().getClassLoader())); - } - catch (Exception e) { - LOG.debug(e); - dataNode.clear(true); - } - } - } - - private static void commit(@NotNull final IdeModifiableModelsProvider modelsProvider, - @NotNull Project project, - boolean synchronous, - @NotNull final String commitDesc) { - ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) { - @Override - public void execute() { - final long startTime = System.currentTimeMillis(); - modelsProvider.commit(); - final long timeInMs = System.currentTimeMillis() - startTime; - LOG.debug(String.format("%s committed in %d ms", commitDesc, timeInMs)); - } - }); - } - - private static void dispose(@NotNull final IdeModifiableModelsProvider modelsProvider, - @NotNull Project project, - boolean synchronous) { - ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) { - @Override - public void execute() { - modelsProvider.dispose(); - } - }); + @Override + public Collection getExternalProjectsData(@NotNull Project project, + @NotNull ProjectSystemId projectSystemId) { + return delegate.getExternalProjectsData(project, projectSystemId); } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManagerImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManagerImpl.java new file mode 100644 index 000000000000..dcdaad0854b1 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManagerImpl.java @@ -0,0 +1,416 @@ +/* + * Copyright 2000-2013 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.externalSystem.service.project.manage; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.externalSystem.model.*; +import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.model.project.ProjectData; +import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider; +import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl; +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager; +import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; +import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.impl.ProjectImpl; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.NotNullLazyValue; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ExceptionUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.ContainerUtilRt; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +import static com.intellij.util.containers.ContainerUtil.map2Array; + +/** + * Aggregates all {@link ProjectDataService#EP_NAME registered data services} and provides entry points for project data management. + * + * @author Denis Zhdanov + * @since 4/16/13 11:38 AM + */ +public class ProjectDataManagerImpl implements ProjectDataManager { + + private static final Logger LOG = Logger.getInstance("#" + ProjectDataManagerImpl.class.getName()); + private static final com.intellij.openapi.util.Key DATA_READY = + com.intellij.openapi.util.Key.create("externalSystem.data.ready"); + + @NotNull private final NotNullLazyValue, List>>> myServices; + + public static ProjectDataManagerImpl getInstance() { + ProjectDataManager service = ServiceManager.getService(ProjectDataManager.class); + return (ProjectDataManagerImpl)service; + } + + public ProjectDataManagerImpl() { + myServices = new NotNullLazyValue, List>>>() { + @NotNull + @Override + protected Map, List>> compute() { + Map, List>> result = ContainerUtilRt.newHashMap(); + for (ProjectDataService service : ProjectDataService.EP_NAME.getExtensions()) { + List> services = result.get(service.getTargetDataKey()); + if (services == null) { + result.put(service.getTargetDataKey(), services = ContainerUtilRt.newArrayList()); + } + services.add(service); + } + + for (List> services : result.values()) { + ExternalSystemApiUtil.orderAwareSort(services); + } + return result; + } + }; + } + + @SuppressWarnings("unchecked") + @Override + public void importData(@NotNull Collection> nodes, + @NotNull Project project, + @NotNull IdeModifiableModelsProvider modelsProvider, + boolean synchronous) { + if (project.isDisposed()) return; + + MultiMap, DataNode> grouped = ExternalSystemApiUtil.recursiveGroup(nodes); + for (Key key : myServices.getValue().keySet()) { + if (!grouped.containsKey(key)) { + grouped.put(key, Collections.emptyList()); + } + } + + final Collection> projects = grouped.get(ProjectKeys.PROJECT); + // only one project(can be multi-module project) expected for per single import + assert projects.size() == 1 || projects.isEmpty(); + + final DataNode projectNode = (DataNode)ContainerUtil.getFirstItem(projects); + final ProjectData projectData; + ProjectSystemId projectSystemId; + if (projectNode != null) { + projectData = projectNode.getData(); + projectSystemId = projectNode.getData().getOwner(); + ExternalProjectsDataStorage.getInstance(project).saveInclusionSettings(projectNode); + } + else { + projectData = null; + DataNode aModuleNode = (DataNode)ContainerUtil.getFirstItem(grouped.get(ProjectKeys.MODULE)); + projectSystemId = aModuleNode != null ? aModuleNode.getData().getOwner() : null; + } + + if (projectSystemId != null) { + ExternalSystemUtil.scheduleExternalViewStructureUpdate(project, projectSystemId); + } + + List onSuccessImportTasks = ContainerUtil.newSmartList(); + try { + final Set, Collection>>> entries = grouped.entrySet(); + final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + if (indicator != null) { + indicator.setIndeterminate(false); + } + final int size = entries.size(); + int count = 0; + List postImportTasks = ContainerUtil.newSmartList(); + for (Map.Entry, Collection>> entry : entries) { + if (indicator != null) { + String message = ExternalSystemBundle.message( + "progress.update.text", projectSystemId != null ? projectSystemId.getReadableName() : "", + "Refresh " + getReadableText(entry.getKey())); + indicator.setText(message); + indicator.setFraction((double)count++ / size); + } + doImportData(entry.getKey(), entry.getValue(), projectData, project, modelsProvider, postImportTasks, onSuccessImportTasks); + } + + for (Runnable postImportTask : postImportTasks) { + postImportTask.run(); + } + + commit(modelsProvider, project, synchronous, "Imported data"); + if (indicator != null) { + indicator.setIndeterminate(true); + } + + project.getMessageBus().syncPublisher(ProjectDataImportListener.TOPIC) + .onImportFinished(projectData != null ? projectData.getLinkedExternalProjectPath() : null); + } + catch (Throwable t) { + dispose(modelsProvider, project, synchronous); + ExceptionUtil.rethrowAllAsUnchecked(t); + } + + for (Runnable onSuccessImportTask : ContainerUtil.reverse(onSuccessImportTasks)) { + onSuccessImportTask.run(); + } + } + + @NotNull + private static String getReadableText(@NotNull Key key) { + StringBuilder buffer = new StringBuilder(); + String s = key.toString(); + for (int i = 0; i < s.length(); i++) { + char currChar = s.charAt(i); + if (Character.isUpperCase(currChar)) { + if (i != 0) { + buffer.append(' '); + } + buffer.append(StringUtil.toLowerCase(currChar)); + } + else { + buffer.append(currChar); + } + } + return buffer.toString(); + } + + @Override + public void importData(@NotNull Collection> nodes, @NotNull Project project, boolean synchronous) { + Collection> dummy = ContainerUtil.newSmartList(); + dummy.addAll(nodes); + importData(dummy, project, new IdeModifiableModelsProviderImpl(project), synchronous); + } + + @Override + public void importData(@NotNull DataNode node, + @NotNull Project project, + @NotNull IdeModifiableModelsProvider modelsProvider, + boolean synchronous) { + Collection> dummy = ContainerUtil.newSmartList(); + dummy.add(node); + importData(dummy, project, modelsProvider, synchronous); + } + + @Override + public void importData(@NotNull DataNode node, + @NotNull Project project, + boolean synchronous) { + importData(node, project, new IdeModifiableModelsProviderImpl(project), synchronous); + } + + @SuppressWarnings("unchecked") + private void doImportData(@NotNull Key key, + @NotNull Collection> nodes, + @Nullable final ProjectData projectData, + @NotNull final Project project, + @NotNull final IdeModifiableModelsProvider modelsProvider, + @NotNull final List postImportTasks, + @NotNull final List onSuccessImportTasks) { + if (project.isDisposed()) return; + if (project instanceof ProjectImpl) { + assert ((ProjectImpl)project).isComponentsCreated(); + } + + final List> toImport = ContainerUtil.newSmartList(); + final List> toIgnore = ContainerUtil.newSmartList(); + + for (DataNode node : nodes) { + if (!key.equals(node.getKey())) continue; + + if (node.isIgnored()) { + toIgnore.add(node); + } + else { + toImport.add(node); + } + } + + ensureTheDataIsReadyToUse((Collection)toImport); + + final List> services = myServices.getValue().get(key); + if (services == null) { + LOG.warn(String.format( + "Can't import data nodes '%s'. Reason: no service is registered for key %s. Available services for %s", + toImport, key, myServices.getValue().keySet() + )); + } + else { + for (ProjectDataService service : services) { + final long importStartTime = System.currentTimeMillis(); + ((ProjectDataService)service).importData(toImport, projectData, project, modelsProvider); + if (LOG.isDebugEnabled()) { + final long importTimeInMs = (System.currentTimeMillis() - importStartTime); + LOG.debug(String.format("Service %s imported data in %d ms", service.getClass().getSimpleName(), importTimeInMs)); + } + + if (projectData != null) { + ensureTheDataIsReadyToUse((Collection)toIgnore); + final long removeStartTime = System.currentTimeMillis(); + final Computable> orphanIdeDataComputable = + ((ProjectDataService)service).computeOrphanData(toImport, projectData, project, modelsProvider); + ((ProjectDataService)service).removeData(orphanIdeDataComputable, toIgnore, projectData, project, modelsProvider); + if (LOG.isDebugEnabled()) { + final long removeTimeInMs = (System.currentTimeMillis() - removeStartTime); + LOG.debug(String.format("Service %s computed and removed data in %d ms", service.getClass().getSimpleName(), removeTimeInMs)); + } + } + } + } + + if (services != null && projectData != null) { + postImportTasks.add(() -> { + for (ProjectDataService service : services) { + if (service instanceof AbstractProjectDataService) { + final long taskStartTime = System.currentTimeMillis(); + ((AbstractProjectDataService)service).postProcess(toImport, projectData, project, modelsProvider); + if (LOG.isDebugEnabled()) { + final long taskTimeInMs = (System.currentTimeMillis() - taskStartTime); + LOG.debug(String.format("Service %s run post import task in %d ms", service.getClass().getSimpleName(), taskTimeInMs)); + } + } + } + }); + onSuccessImportTasks.add(() -> { + for (ProjectDataService service : services) { + if (service instanceof AbstractProjectDataService) { + final long taskStartTime = System.currentTimeMillis(); + ((AbstractProjectDataService)service).onSuccessImport(project); + if (LOG.isDebugEnabled()) { + final long taskTimeInMs = (System.currentTimeMillis() - taskStartTime); + LOG.debug(String.format("Service %s run post import task in %d ms", service.getClass().getSimpleName(), taskTimeInMs)); + } + } + } + }); + } + } + + @Override + public void ensureTheDataIsReadyToUse(@Nullable DataNode dataNode) { + if (dataNode == null) return; + if (Boolean.TRUE.equals(dataNode.getUserData(DATA_READY))) return; + + ExternalSystemApiUtil.visit(dataNode, dataNode1 -> { + prepareDataToUse(dataNode1); + dataNode1.putUserData(DATA_READY, Boolean.TRUE); + }); + } + + @SuppressWarnings("unchecked") + public void removeData(@NotNull Key key, + @NotNull Collection toRemove, + @NotNull final Collection> toIgnore, + @NotNull final ProjectData projectData, + @NotNull Project project, + @NotNull final IdeModifiableModelsProvider modelsProvider, + boolean synchronous) { + try { + List> services = myServices.getValue().get(key); + for (ProjectDataService service : services) { + final long removeStartTime = System.currentTimeMillis(); + service.removeData(new Computable.PredefinedValueComputable(toRemove), toIgnore, projectData, project, modelsProvider); + if (LOG.isDebugEnabled()) { + final long removeTimeInMs = System.currentTimeMillis() - removeStartTime; + LOG.debug(String.format("Service %s removed data in %d ms", service.getClass().getSimpleName(), removeTimeInMs)); + } + } + + commit(modelsProvider, project, synchronous, "Removed data"); + } + catch (Throwable t) { + dispose(modelsProvider, project, synchronous); + ExceptionUtil.rethrowAllAsUnchecked(t); + } + } + + public void removeData(@NotNull Key key, + @NotNull Collection toRemove, + @NotNull final Collection> toIgnore, + @NotNull final ProjectData projectData, + @NotNull Project project, + boolean synchronous) { + removeData(key, toRemove, toIgnore, projectData, project, new IdeModifiableModelsProviderImpl(project), synchronous); + } + + public void updateExternalProjectData(@NotNull Project project, @NotNull ExternalProjectInfo externalProjectInfo) { + if (!project.isDisposed()) { + ExternalProjectsManagerImpl.getInstance(project).updateExternalProjectData(externalProjectInfo); + } + } + + @Nullable + @Override + public ExternalProjectInfo getExternalProjectData(@NotNull Project project, + @NotNull ProjectSystemId projectSystemId, + @NotNull String externalProjectPath) { + return !project.isDisposed() ? ExternalProjectsDataStorage.getInstance(project).get(projectSystemId, externalProjectPath) : null; + } + + @NotNull + @Override + public Collection getExternalProjectsData(@NotNull Project project, @NotNull ProjectSystemId projectSystemId) { + if (!project.isDisposed()) { + return ExternalProjectsDataStorage.getInstance(project).list(projectSystemId); + } + else { + return ContainerUtil.emptyList(); + } + } + + private void ensureTheDataIsReadyToUse(@NotNull Collection> nodes) { + for (DataNode node : nodes) { + ensureTheDataIsReadyToUse(node); + } + } + + private void prepareDataToUse(@NotNull DataNode dataNode) { + final Map, List>> servicesByKey = myServices.getValue(); + List> services = servicesByKey.get(dataNode.getKey()); + if (services != null) { + try { + dataNode.prepareData(map2Array(services, ClassLoader.class, service -> service.getClass().getClassLoader())); + } + catch (Exception e) { + LOG.debug(e); + dataNode.clear(true); + } + } + } + + private static void commit(@NotNull final IdeModifiableModelsProvider modelsProvider, + @NotNull Project project, + boolean synchronous, + @NotNull final String commitDesc) { + ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) { + @Override + public void execute() { + final long startTime = System.currentTimeMillis(); + modelsProvider.commit(); + final long timeInMs = System.currentTimeMillis() - startTime; + LOG.debug(String.format("%s committed in %d ms", commitDesc, timeInMs)); + } + }); + } + + private static void dispose(@NotNull final IdeModifiableModelsProvider modelsProvider, + @NotNull Project project, + boolean synchronous) { + ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) { + @Override + public void execute() { + modelsProvider.dispose(); + } + }); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/wizard/AbstractExternalProjectImportBuilder.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/wizard/AbstractExternalProjectImportBuilder.java index 7ce64b7be2d5..2e8020570867 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/wizard/AbstractExternalProjectImportBuilder.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/wizard/AbstractExternalProjectImportBuilder.java @@ -13,11 +13,7 @@ import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.internal.InternalExternalProjectInfo; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; -import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback; -import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider; -import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl; -import com.intellij.openapi.externalSystem.service.project.IdeUIModifiableModelsProvider; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.*; import com.intellij.openapi.externalSystem.service.settings.AbstractImportFromExternalSystemControl; import com.intellij.openapi.externalSystem.service.ui.ExternalProjectDataSelectorDialog; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; @@ -71,6 +67,15 @@ public abstract class AbstractExternalProjectImportBuilder myExternalProjectNode; + /** + * @deprecated use {@link AbstractExternalProjectImportBuilder#AbstractExternalProjectImportBuilder(ProjectDataManager, AbstractImportFromExternalSystemControl, ProjectSystemId)} + */ + public AbstractExternalProjectImportBuilder(@NotNull com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager projectDataManager, + @NotNull C control, + @NotNull ProjectSystemId externalSystemId) { + this((ProjectDataManager)projectDataManager, control, externalSystemId); + } + public AbstractExternalProjectImportBuilder(@NotNull ProjectDataManager projectDataManager, @NotNull C control, @NotNull ProjectSystemId externalSystemId) diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/AbstractExternalSystemToolWindowFactory.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/AbstractExternalSystemToolWindowFactory.java index 49f5d05c0609..41fe11678801 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/AbstractExternalSystemToolWindowFactory.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/AbstractExternalSystemToolWindowFactory.java @@ -16,7 +16,7 @@ package com.intellij.openapi.externalSystem.service.task.ui; import com.intellij.openapi.externalSystem.model.ProjectSystemId; -import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; import com.intellij.openapi.externalSystem.view.ExternalProjectsViewImpl; import com.intellij.openapi.project.DumbAware; @@ -45,7 +45,7 @@ public abstract class AbstractExternalSystemToolWindowFactory implements ToolWin toolWindow.setTitle(myExternalSystemId.getReadableName()); ContentManager contentManager = toolWindow.getContentManager(); final ExternalProjectsViewImpl projectsView = new ExternalProjectsViewImpl(project, (ToolWindowEx)toolWindow, myExternalSystemId); - ExternalProjectsManager.getInstance(project).registerView(projectsView); + ExternalProjectsManagerImpl.getInstance(project).registerView(projectsView); ContentImpl tasksContent = new ContentImpl(projectsView, ExternalSystemBundle.message("tool.window.title.projects"), true); contentManager.addContent(tasksContent); } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ConfigureTasksActivationDialog.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ConfigureTasksActivationDialog.java index ff8cb1d5c682..573caa240402 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ConfigureTasksActivationDialog.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ConfigureTasksActivationDialog.java @@ -27,9 +27,10 @@ import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; import com.intellij.openapi.externalSystem.model.ProjectKeys; import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl.ExternalProjectsStateProvider; import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator.Phase; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; import com.intellij.openapi.externalSystem.service.project.manage.TaskActivationState; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; @@ -67,8 +68,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.*; -import static com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager.ExternalProjectsStateProvider; -import static com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager.getInstance; +import static com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl.getInstance; import static com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator.TaskActivationEntry; /** diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/ExternalProjectDataSelectorDialog.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/ExternalProjectDataSelectorDialog.java index 96461c020e32..cd7f5336ce84 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/ExternalProjectDataSelectorDialog.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/ExternalProjectDataSelectorDialog.java @@ -31,7 +31,8 @@ import com.intellij.openapi.externalSystem.model.project.Identifiable; import com.intellij.openapi.externalSystem.model.project.ModuleData; import com.intellij.openapi.externalSystem.model.project.ModuleDependencyData; import com.intellij.openapi.externalSystem.model.project.ProjectData; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil; @@ -123,7 +124,7 @@ public class ExternalProjectDataSelectorDialog extends DialogWrapper { } private void init(@NotNull ExternalProjectInfo projectInfo) { - ProjectDataManager.getInstance().ensureTheDataIsReadyToUse(projectInfo.getExternalProjectStructure()); + ProjectDataManagerImpl.getInstance().ensureTheDataIsReadyToUse(projectInfo.getExternalProjectStructure()); myProjectInfo = projectInfo; myExternalSystemUiAware = ExternalSystemUiUtil.getUiAware(myProjectInfo.getProjectSystemId()); myTree = createTree(); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/ExternalToolWindowManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/ExternalToolWindowManager.java index aac83b3abc68..5058c4bd6c7f 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/ExternalToolWindowManager.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/ExternalToolWindowManager.java @@ -37,28 +37,22 @@ public class ExternalToolWindowManager { settings.subscribe(new ExternalSystemSettingsListenerAdapter() { @Override public void onProjectsLinked(@NotNull Collection linked) { - if (settings.getLinkedProjectsSettings().size() != 1) { - return; - } ToolWindow toolWindow = getToolWindow(project, manager.getSystemId()); if (toolWindow != null) { toolWindow.setAvailable(true, null); } else { - StartupManager.getInstance(project).runWhenProjectIsInitialized(new DumbAwareRunnable() { - @Override - public void run() { - if (project.isDisposed()) return; + StartupManager.getInstance(project).runWhenProjectIsInitialized((DumbAwareRunnable)() -> { + if (project.isDisposed()) return; - ExternalSystemUtil.ensureToolWindowInitialized(project, manager.getSystemId()); - ToolWindowManager.getInstance(project).invokeLater(() -> { - if (project.isDisposed()) return; - ToolWindow toolWindow1 = getToolWindow(project, manager.getSystemId()); - if (toolWindow1 != null) { - toolWindow1.setAvailable(true, null); - } - }); - } + ExternalSystemUtil.ensureToolWindowInitialized(project, manager.getSystemId()); + ToolWindowManager.getInstance(project).invokeLater(() -> { + if (project.isDisposed()) return; + ToolWindow toolWindow1 = getToolWindow(project, manager.getSystemId()); + if (toolWindow1 != null) { + toolWindow1.setAvailable(true, null); + } + }); }); } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/SelectExternalSystemNodeDialog.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/SelectExternalSystemNodeDialog.java index dd9d38027270..c891721243ef 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/SelectExternalSystemNodeDialog.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/SelectExternalSystemNodeDialog.java @@ -19,8 +19,8 @@ import com.intellij.openapi.externalSystem.model.DataNode; import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.project.ProjectData; -import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl; import com.intellij.openapi.externalSystem.view.ExternalProjectsStructure; import com.intellij.openapi.externalSystem.view.ExternalProjectsView; import com.intellij.openapi.externalSystem.view.ExternalProjectsViewAdapter; @@ -32,7 +32,6 @@ import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.treeStructure.SimpleNode; import com.intellij.ui.treeStructure.SimpleNodeVisitor; import com.intellij.ui.treeStructure.SimpleTree; -import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.tree.TreeUtil; @@ -81,7 +80,7 @@ public class SelectExternalSystemNodeDialog extends DialogWrapper { myTree = new SimpleTree(); myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); - final ExternalProjectsView projectsView = ExternalProjectsManager.getInstance(project).getExternalProjectsView(systemId); + final ExternalProjectsView projectsView = ExternalProjectsManagerImpl.getInstance(project).getExternalProjectsView(systemId); if(projectsView != null) { final ExternalProjectsStructure treeStructure = new ExternalProjectsStructure(project, myTree) { @SuppressWarnings("unchecked") diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java index fd6d6f7cadb4..79b65ff87e9a 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java @@ -52,10 +52,11 @@ import com.intellij.openapi.externalSystem.service.internal.ExternalSystemResolv import com.intellij.openapi.externalSystem.service.notification.ExternalSystemNotificationManager; import com.intellij.openapi.externalSystem.service.notification.NotificationSource; import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback; +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager; import com.intellij.openapi.externalSystem.service.project.manage.ContentRootDataService; -import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl; import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; import com.intellij.openapi.externalSystem.task.TaskCallback; @@ -405,7 +406,7 @@ public class ExternalSystemUtil { .clearNotifications(null, NotificationSource.PROJECT_SYNC, externalSystemId); } - final ExternalSystemTaskActivator externalSystemTaskActivator = ExternalProjectsManager.getInstance(project).getTaskActivator(); + final ExternalSystemTaskActivator externalSystemTaskActivator = ExternalProjectsManagerImpl.getInstance(project).getTaskActivator(); if (!isPreviewMode && !externalSystemTaskActivator.runTasks(externalProjectPath, ExternalSystemTaskActivator.Phase.BEFORE_SYNC)) { return; } @@ -785,7 +786,7 @@ public class ExternalSystemUtil { } public static void scheduleExternalViewStructureUpdate(@NotNull final Project project, @NotNull final ProjectSystemId systemId) { - ExternalProjectsView externalProjectsView = ExternalProjectsManager.getInstance(project).getExternalProjectsView(systemId); + ExternalProjectsView externalProjectsView = ExternalProjectsManagerImpl.getInstance(project).getExternalProjectsView(systemId); if (externalProjectsView instanceof ExternalProjectsViewImpl) { ((ExternalProjectsViewImpl)externalProjectsView).scheduleStructureUpdate(); } @@ -799,7 +800,7 @@ public class ExternalSystemUtil { ExternalSystemApiUtil.getSettings(project, projectSystemId).getLinkedProjectSettings(externalProjectPath); if (linkedProjectSettings == null) return null; - return ProjectDataManager.getInstance().getExternalProjectData( + return ProjectDataManagerImpl.getInstance().getExternalProjectData( project, projectSystemId, linkedProjectSettings.getExternalProjectPath()); } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewImpl.java index 163c20b982c2..bf9431ba98ac 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewImpl.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewImpl.java @@ -31,10 +31,10 @@ import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecution import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.model.task.TaskData; import com.intellij.openapi.externalSystem.service.execution.ExternalSystemTaskLocation; -import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl; import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemShortcutsManager; import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListenerAdapter; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil; @@ -77,7 +77,7 @@ public class ExternalProjectsViewImpl extends SimpleToolWindowPanel implements D @NotNull private final Project myProject; @NotNull - private final ExternalProjectsManager myProjectsManager; + private final ExternalProjectsManagerImpl myProjectsManager; @NotNull private final ToolWindowEx myToolWindow; @NotNull @@ -101,7 +101,7 @@ public class ExternalProjectsViewImpl extends SimpleToolWindowPanel implements D myToolWindow = toolWindow; myExternalSystemId = externalSystemId; myUiAware = ExternalSystemUiUtil.getUiAware(externalSystemId); - myProjectsManager = ExternalProjectsManager.getInstance(myProject); + myProjectsManager = ExternalProjectsManagerImpl.getInstance(myProject); String toolWindowId = toolWindow instanceof ToolWindowImpl ? ((ToolWindowImpl)toolWindow).getId() : myExternalSystemId.getReadableName(); @@ -527,7 +527,7 @@ public class ExternalProjectsViewImpl extends SimpleToolWindowPanel implements D } private List getSelectedNodes(Class aClass) { - return myStructure != null ? myStructure.getSelectedNodes(myTree, aClass) : ContainerUtil.emptyList(); + return myStructure != null ? myStructure.getSelectedNodes(myTree, aClass) : ContainerUtil.emptyList(); } private List getSelectedProjectNodes() { diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/AbstractExternalSystemTest.groovy b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/AbstractExternalSystemTest.groovy index cbb967d50584..2b774bb8bdc6 100644 --- a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/AbstractExternalSystemTest.groovy +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/AbstractExternalSystemTest.groovy @@ -14,19 +14,17 @@ * limitations under the License. */ package com.intellij.openapi.externalSystem.test + import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.extensions.ExtensionPoint import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.externalSystem.ExternalSystemManager import com.intellij.openapi.externalSystem.model.DataNode import com.intellij.openapi.externalSystem.model.project.ProjectData -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager -import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.project.Project -import com.intellij.openapi.roots.ex.ProjectRootManagerEx import com.intellij.openapi.util.io.FileUtil -import com.intellij.testFramework.PlatformTestCase import com.intellij.testFramework.SkipInHeadlessEnvironment import com.intellij.testFramework.UsefulTestCase import com.intellij.testFramework.fixtures.IdeaProjectTestFixture @@ -37,6 +35,7 @@ import org.jetbrains.annotations.Nullable import java.lang.reflect.Field import java.lang.reflect.Modifier + /** * @author Denis Zhdanov * @since 8/7/13 2:04 PM diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemImportingTestCase.java b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemImportingTestCase.java index 465ea6900ea6..0aab905163b5 100644 --- a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemImportingTestCase.java +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemImportingTestCase.java @@ -15,8 +15,6 @@ */ package com.intellij.openapi.externalSystem.test; -import com.intellij.openapi.application.AccessToken; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.ex.CompilerPathsEx; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder; @@ -26,7 +24,8 @@ import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback; -import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; @@ -45,14 +44,12 @@ import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.packaging.artifacts.Artifact; import com.intellij.packaging.artifacts.ArtifactManager; import com.intellij.testFramework.IdeaTestUtil; import com.intellij.util.BooleanFunction; -import com.intellij.util.Consumer; import com.intellij.util.Function; import com.intellij.util.PathUtil; import com.intellij.util.containers.ContainerUtil; @@ -162,7 +159,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest List actual = new ArrayList<>(); for (ContentEntry contentRoot : contentRoots) { for (SourceFolder f : contentRoot.getSourceFolders(rootType)) { - rootUrl = rootUrl == null ? VirtualFileManager.extractPath(contentRoot.getUrl()) : VirtualFileManager.extractPath(rootUrl); + rootUrl = VirtualFileManager.extractPath(rootUrl == null ? contentRoot.getUrl() : rootUrl); String folderUrl = VirtualFileManager.extractPath(f.getUrl()); if (folderUrl.startsWith(rootUrl)) { int length = rootUrl.length() + 1; @@ -215,7 +212,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest } private static String getAbsolutePath(String path) { - path = VfsUtil.urlToPath(path); + path = VfsUtilCore.urlToPath(path); path = PathUtil.getCanonicalPath(path); return FileUtil.toSystemIndependentName(path); } @@ -364,28 +361,12 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest protected void assertArtifacts(String... expectedNames) { final List actualNames = ContainerUtil.map( - ArtifactManager.getInstance(myProject).getAllArtifactsIncludingInvalid(), new Function() { - @Override - public String fun(Artifact artifact) { - return artifact.getName(); - } - }); + ArtifactManager.getInstance(myProject).getAllArtifactsIncludingInvalid(), + (Function)artifact -> artifact.getName()); assertUnorderedElementsAreEqual(actualNames, expectedNames); } - protected Module getModule(final String name) { - AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock(); - try { - Module m = ModuleManager.getInstance(myProject).findModuleByName(name); - assertNotNull("Module " + name + " not found", m); - return m; - } - finally { - accessToken.finish(); - } - } - private ContentEntry getContentRoot(String moduleName) { ContentEntry[] ee = getContentRoots(moduleName); List roots = new ArrayList<>(); @@ -415,7 +396,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest } protected void ignoreData(BooleanFunction> booleanFunction, final boolean ignored) { - final ExternalProjectInfo externalProjectInfo = ProjectDataManager.getInstance().getExternalProjectData( + final ExternalProjectInfo externalProjectInfo = ProjectDataManagerImpl.getInstance().getExternalProjectData( myProject, getExternalSystemId(), getCurrentExternalProjectSettings().getExternalProjectPath()); assertNotNull(externalProjectInfo); diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestCase.java b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestCase.java index 68f0a00e0f91..8a08eeadeecc 100644 --- a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestCase.java +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestCase.java @@ -462,9 +462,13 @@ public abstract class ExternalSystemTestCase extends UsefulTestCase { } protected Module getModule(final String name) { + return getModule(myProject, name); + } + + protected Module getModule(Project project, String name) { AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock(); try { - Module m = ModuleManager.getInstance(myProject).findModuleByName(name); + Module m = ModuleManager.getInstance(project).findModuleByName(name); assertNotNull("Module " + name + " not found", m); return m; } diff --git a/platform/icons/src/actions/checked.png b/platform/icons/src/actions/checked.png index 1de39421bc90..012db846e702 100644 Binary files a/platform/icons/src/actions/checked.png and b/platform/icons/src/actions/checked.png differ diff --git a/platform/icons/src/actions/checked@2x.png b/platform/icons/src/actions/checked@2x.png index 7ef960bcf244..fb29f5a3683d 100644 Binary files a/platform/icons/src/actions/checked@2x.png and b/platform/icons/src/actions/checked@2x.png differ diff --git a/platform/icons/src/actions/checked@2x_dark.png b/platform/icons/src/actions/checked@2x_dark.png index f08209140e9a..fb29f5a3683d 100644 Binary files a/platform/icons/src/actions/checked@2x_dark.png and b/platform/icons/src/actions/checked@2x_dark.png differ diff --git a/platform/icons/src/actions/checkedBlack.png b/platform/icons/src/actions/checkedBlack.png index 1de39421bc90..012db846e702 100644 Binary files a/platform/icons/src/actions/checkedBlack.png and b/platform/icons/src/actions/checkedBlack.png differ diff --git a/platform/icons/src/actions/checkedBlack@2x.png b/platform/icons/src/actions/checkedBlack@2x.png index 7ef960bcf244..fb29f5a3683d 100644 Binary files a/platform/icons/src/actions/checkedBlack@2x.png and b/platform/icons/src/actions/checkedBlack@2x.png differ diff --git a/platform/icons/src/actions/checkedGrey.png b/platform/icons/src/actions/checkedGrey.png index 6172daa35db7..012db846e702 100644 Binary files a/platform/icons/src/actions/checkedGrey.png and b/platform/icons/src/actions/checkedGrey.png differ diff --git a/platform/icons/src/actions/checkedGrey@2x.png b/platform/icons/src/actions/checkedGrey@2x.png index f08209140e9a..fb29f5a3683d 100644 Binary files a/platform/icons/src/actions/checkedGrey@2x.png and b/platform/icons/src/actions/checkedGrey@2x.png differ diff --git a/platform/icons/src/actions/checked_dark.png b/platform/icons/src/actions/checked_dark.png index 6172daa35db7..012db846e702 100644 Binary files a/platform/icons/src/actions/checked_dark.png and b/platform/icons/src/actions/checked_dark.png differ diff --git a/platform/icons/src/actions/checked_selected.png b/platform/icons/src/actions/checked_selected.png index 4c756e21131a..6c3847f7e7b3 100644 Binary files a/platform/icons/src/actions/checked_selected.png and b/platform/icons/src/actions/checked_selected.png differ diff --git a/platform/icons/src/actions/checked_selected@2x.png b/platform/icons/src/actions/checked_selected@2x.png index 156efbebc035..2c377210d0e4 100644 Binary files a/platform/icons/src/actions/checked_selected@2x.png and b/platform/icons/src/actions/checked_selected@2x.png differ diff --git a/platform/icons/src/actions/checked_small.png b/platform/icons/src/actions/checked_small.png index eaf1718e664b..47a244cdaaeb 100644 Binary files a/platform/icons/src/actions/checked_small.png and b/platform/icons/src/actions/checked_small.png differ diff --git a/platform/icons/src/actions/checked_small@2x.png b/platform/icons/src/actions/checked_small@2x.png index 08a80ae267d1..20fa1371a7a7 100644 Binary files a/platform/icons/src/actions/checked_small@2x.png and b/platform/icons/src/actions/checked_small@2x.png differ diff --git a/platform/icons/src/actions/checked_small@2x_dark.png b/platform/icons/src/actions/checked_small@2x_dark.png index 530bdb5feb9f..20fa1371a7a7 100644 Binary files a/platform/icons/src/actions/checked_small@2x_dark.png and b/platform/icons/src/actions/checked_small@2x_dark.png differ diff --git a/platform/icons/src/actions/checked_small_dark.png b/platform/icons/src/actions/checked_small_dark.png index 109d5e23d7e4..47a244cdaaeb 100644 Binary files a/platform/icons/src/actions/checked_small_dark.png and b/platform/icons/src/actions/checked_small_dark.png differ diff --git a/platform/icons/src/actions/checked_small_selected.png b/platform/icons/src/actions/checked_small_selected.png index c66b54341bc7..2cce47240913 100644 Binary files a/platform/icons/src/actions/checked_small_selected.png and b/platform/icons/src/actions/checked_small_selected.png differ diff --git a/platform/icons/src/actions/checked_small_selected@2x.png b/platform/icons/src/actions/checked_small_selected@2x.png index 02e77552d24a..6f316f5c111f 100644 Binary files a/platform/icons/src/actions/checked_small_selected@2x.png and b/platform/icons/src/actions/checked_small_selected@2x.png differ diff --git a/platform/icons/src/actions/diagramDiff.png b/platform/icons/src/actions/diagramDiff.png new file mode 100644 index 000000000000..6bdb05a87677 Binary files /dev/null and b/platform/icons/src/actions/diagramDiff.png differ diff --git a/platform/icons/src/actions/diagramDiff@2x.png b/platform/icons/src/actions/diagramDiff@2x.png new file mode 100644 index 000000000000..a7d7471ae35d Binary files /dev/null and b/platform/icons/src/actions/diagramDiff@2x.png differ diff --git a/platform/icons/src/actions/diff.png b/platform/icons/src/actions/diff.png index 5addd2e2ed6f..718a45c6895e 100644 Binary files a/platform/icons/src/actions/diff.png and b/platform/icons/src/actions/diff.png differ diff --git a/platform/icons/src/actions/diff@2x.png b/platform/icons/src/actions/diff@2x.png index 298b2a0b3f53..6feb91355937 100644 Binary files a/platform/icons/src/actions/diff@2x.png and b/platform/icons/src/actions/diff@2x.png differ diff --git a/platform/icons/src/actions/diff@2x_dark.png b/platform/icons/src/actions/diff@2x_dark.png deleted file mode 100644 index 731d762d0d62..000000000000 Binary files a/platform/icons/src/actions/diff@2x_dark.png and /dev/null differ diff --git a/platform/icons/src/actions/diffPreview.png b/platform/icons/src/actions/diffPreview.png new file mode 100644 index 000000000000..d441c0243860 Binary files /dev/null and b/platform/icons/src/actions/diffPreview.png differ diff --git a/platform/icons/src/actions/diffPreview@2x.png b/platform/icons/src/actions/diffPreview@2x.png new file mode 100644 index 000000000000..b829c27cf634 Binary files /dev/null and b/platform/icons/src/actions/diffPreview@2x.png differ diff --git a/platform/icons/src/actions/diffWithClipboard.png b/platform/icons/src/actions/diffWithClipboard.png new file mode 100644 index 000000000000..b0e4d6ac4848 Binary files /dev/null and b/platform/icons/src/actions/diffWithClipboard.png differ diff --git a/platform/icons/src/actions/diffWithClipboard@2x.png b/platform/icons/src/actions/diffWithClipboard@2x.png new file mode 100644 index 000000000000..82548066add3 Binary files /dev/null and b/platform/icons/src/actions/diffWithClipboard@2x.png differ diff --git a/platform/icons/src/actions/diffWithCurrent.png b/platform/icons/src/actions/diffWithCurrent.png index 84c4874f30a1..f8180e925c3b 100644 Binary files a/platform/icons/src/actions/diffWithCurrent.png and b/platform/icons/src/actions/diffWithCurrent.png differ diff --git a/platform/icons/src/actions/diffWithCurrent@2x.png b/platform/icons/src/actions/diffWithCurrent@2x.png index 7da53a5eb964..266d039f633c 100644 Binary files a/platform/icons/src/actions/diffWithCurrent@2x.png and b/platform/icons/src/actions/diffWithCurrent@2x.png differ diff --git a/platform/icons/src/actions/diffWithCurrent@2x_dark.png b/platform/icons/src/actions/diffWithCurrent@2x_dark.png deleted file mode 100644 index 8bd2e2ca3c78..000000000000 Binary files a/platform/icons/src/actions/diffWithCurrent@2x_dark.png and /dev/null differ diff --git a/platform/icons/src/actions/diffWithCurrent_dark.png b/platform/icons/src/actions/diffWithCurrent_dark.png deleted file mode 100644 index 303603da35a0..000000000000 Binary files a/platform/icons/src/actions/diffWithCurrent_dark.png and /dev/null differ diff --git a/platform/icons/src/actions/diff_dark.png b/platform/icons/src/actions/diff_dark.png deleted file mode 100644 index eeb0c2e07890..000000000000 Binary files a/platform/icons/src/actions/diff_dark.png and /dev/null differ diff --git a/platform/icons/src/actions/listChanges.png b/platform/icons/src/actions/listChanges.png new file mode 100644 index 000000000000..6bd92cf2fcec Binary files /dev/null and b/platform/icons/src/actions/listChanges.png differ diff --git a/platform/icons/src/actions/listChanges@2x.png b/platform/icons/src/actions/listChanges@2x.png new file mode 100644 index 000000000000..1740b40ae999 Binary files /dev/null and b/platform/icons/src/actions/listChanges@2x.png differ diff --git a/platform/icons/src/debugger/selfreference.png b/platform/icons/src/debugger/selfreference.png index 71b18d1765e5..c526e9281892 100644 Binary files a/platform/icons/src/debugger/selfreference.png and b/platform/icons/src/debugger/selfreference.png differ diff --git a/platform/icons/src/debugger/selfreference@2x.png b/platform/icons/src/debugger/selfreference@2x.png index 3f96b3914dfd..a345539d7d3a 100644 Binary files a/platform/icons/src/debugger/selfreference@2x.png and b/platform/icons/src/debugger/selfreference@2x.png differ diff --git a/platform/icons/src/debugger/selfreference@2x_dark.png b/platform/icons/src/debugger/selfreference@2x_dark.png new file mode 100644 index 000000000000..4ed1065a3b78 Binary files /dev/null and b/platform/icons/src/debugger/selfreference@2x_dark.png differ diff --git a/platform/icons/src/debugger/selfreference_dark.png b/platform/icons/src/debugger/selfreference_dark.png new file mode 100644 index 000000000000..dacebfd72617 Binary files /dev/null and b/platform/icons/src/debugger/selfreference_dark.png differ diff --git a/platform/icons/src/diff/Diff.png b/platform/icons/src/diff/Diff.png index a105010a9642..718a45c6895e 100644 Binary files a/platform/icons/src/diff/Diff.png and b/platform/icons/src/diff/Diff.png differ diff --git a/platform/icons/src/diff/Diff@2x.png b/platform/icons/src/diff/Diff@2x.png index a547dcaa8dfb..6feb91355937 100644 Binary files a/platform/icons/src/diff/Diff@2x.png and b/platform/icons/src/diff/Diff@2x.png differ diff --git a/platform/icons/src/diff/Diff@2x_dark.png b/platform/icons/src/diff/Diff@2x_dark.png deleted file mode 100644 index d2176bd90cda..000000000000 Binary files a/platform/icons/src/diff/Diff@2x_dark.png and /dev/null differ diff --git a/platform/icons/src/diff/Diff_dark.png b/platform/icons/src/diff/Diff_dark.png deleted file mode 100644 index b1df05ce5f93..000000000000 Binary files a/platform/icons/src/diff/Diff_dark.png and /dev/null differ diff --git a/platform/icons/src/diff/applyNotConflicts.png b/platform/icons/src/diff/applyNotConflicts.png index ea3923e5b478..0f86aa5edfa4 100644 Binary files a/platform/icons/src/diff/applyNotConflicts.png and b/platform/icons/src/diff/applyNotConflicts.png differ diff --git a/platform/icons/src/diff/applyNotConflicts@2x.png b/platform/icons/src/diff/applyNotConflicts@2x.png index 6961b00223a3..556d7ec0efd8 100644 Binary files a/platform/icons/src/diff/applyNotConflicts@2x.png and b/platform/icons/src/diff/applyNotConflicts@2x.png differ diff --git a/platform/icons/src/diff/applyNotConflicts@2x_dark.png b/platform/icons/src/diff/applyNotConflicts@2x_dark.png deleted file mode 100644 index 6a2772fe888e..000000000000 Binary files a/platform/icons/src/diff/applyNotConflicts@2x_dark.png and /dev/null differ diff --git a/platform/icons/src/diff/applyNotConflictsLeft.png b/platform/icons/src/diff/applyNotConflictsLeft.png index dc8d5b20c579..3a5277cf0f8d 100644 Binary files a/platform/icons/src/diff/applyNotConflictsLeft.png and b/platform/icons/src/diff/applyNotConflictsLeft.png differ diff --git a/platform/icons/src/diff/applyNotConflictsLeft@2x.png b/platform/icons/src/diff/applyNotConflictsLeft@2x.png index 996899a61ad9..5d694f67d28c 100644 Binary files a/platform/icons/src/diff/applyNotConflictsLeft@2x.png and b/platform/icons/src/diff/applyNotConflictsLeft@2x.png differ diff --git a/platform/icons/src/diff/applyNotConflictsLeft@2x_dark.png b/platform/icons/src/diff/applyNotConflictsLeft@2x_dark.png deleted file mode 100644 index 07fd5c7c5136..000000000000 Binary files a/platform/icons/src/diff/applyNotConflictsLeft@2x_dark.png and /dev/null differ diff --git a/platform/icons/src/diff/applyNotConflictsLeft_dark.png b/platform/icons/src/diff/applyNotConflictsLeft_dark.png deleted file mode 100644 index 0fb8f52b71cd..000000000000 Binary files a/platform/icons/src/diff/applyNotConflictsLeft_dark.png and /dev/null differ diff --git a/platform/icons/src/diff/applyNotConflictsRight.png b/platform/icons/src/diff/applyNotConflictsRight.png index ac824b76388d..0d9be054847f 100644 Binary files a/platform/icons/src/diff/applyNotConflictsRight.png and b/platform/icons/src/diff/applyNotConflictsRight.png differ diff --git a/platform/icons/src/diff/applyNotConflictsRight@2x.png b/platform/icons/src/diff/applyNotConflictsRight@2x.png index ac89f53cd1f0..6f14c9ee5492 100644 Binary files a/platform/icons/src/diff/applyNotConflictsRight@2x.png and b/platform/icons/src/diff/applyNotConflictsRight@2x.png differ diff --git a/platform/icons/src/diff/applyNotConflictsRight@2x_dark.png b/platform/icons/src/diff/applyNotConflictsRight@2x_dark.png deleted file mode 100644 index acd14a87b2e9..000000000000 Binary files a/platform/icons/src/diff/applyNotConflictsRight@2x_dark.png and /dev/null differ diff --git a/platform/icons/src/diff/applyNotConflictsRight_dark.png b/platform/icons/src/diff/applyNotConflictsRight_dark.png deleted file mode 100644 index e7e0c13640ba..000000000000 Binary files a/platform/icons/src/diff/applyNotConflictsRight_dark.png and /dev/null differ diff --git a/platform/icons/src/diff/applyNotConflicts_dark.png b/platform/icons/src/diff/applyNotConflicts_dark.png deleted file mode 100644 index 77e0b6c766ca..000000000000 Binary files a/platform/icons/src/diff/applyNotConflicts_dark.png and /dev/null differ diff --git a/platform/icons/src/diff/compare4LeftBottom.png b/platform/icons/src/diff/compare4LeftBottom.png new file mode 100644 index 000000000000..3910eed462b5 Binary files /dev/null and b/platform/icons/src/diff/compare4LeftBottom.png differ diff --git a/platform/icons/src/diff/compare4LeftBottom@2x.png b/platform/icons/src/diff/compare4LeftBottom@2x.png new file mode 100644 index 000000000000..1fc08274a467 Binary files /dev/null and b/platform/icons/src/diff/compare4LeftBottom@2x.png differ diff --git a/platform/icons/src/diff/compare4LeftMiddle.png b/platform/icons/src/diff/compare4LeftMiddle.png new file mode 100644 index 000000000000..7903ef42201a Binary files /dev/null and b/platform/icons/src/diff/compare4LeftMiddle.png differ diff --git a/platform/icons/src/diff/compare4LeftMiddle@2x.png b/platform/icons/src/diff/compare4LeftMiddle@2x.png new file mode 100644 index 000000000000..7614786b1a85 Binary files /dev/null and b/platform/icons/src/diff/compare4LeftMiddle@2x.png differ diff --git a/platform/icons/src/diff/compare4LeftRight.png b/platform/icons/src/diff/compare4LeftRight.png new file mode 100644 index 000000000000..391564deaf9c Binary files /dev/null and b/platform/icons/src/diff/compare4LeftRight.png differ diff --git a/platform/icons/src/diff/compare4LeftRight@2x.png b/platform/icons/src/diff/compare4LeftRight@2x.png new file mode 100644 index 000000000000..bc364e788a4c Binary files /dev/null and b/platform/icons/src/diff/compare4LeftRight@2x.png differ diff --git a/platform/icons/src/diff/compare4MiddleBottom.png b/platform/icons/src/diff/compare4MiddleBottom.png new file mode 100644 index 000000000000..6c2f0e29ea53 Binary files /dev/null and b/platform/icons/src/diff/compare4MiddleBottom.png differ diff --git a/platform/icons/src/diff/compare4MiddleBottom@2x.png b/platform/icons/src/diff/compare4MiddleBottom@2x.png new file mode 100644 index 000000000000..e12cc808b7d9 Binary files /dev/null and b/platform/icons/src/diff/compare4MiddleBottom@2x.png differ diff --git a/platform/icons/src/diff/compare4MiddleRight.png b/platform/icons/src/diff/compare4MiddleRight.png new file mode 100644 index 000000000000..cf6d951e1833 Binary files /dev/null and b/platform/icons/src/diff/compare4MiddleRight.png differ diff --git a/platform/icons/src/diff/compare4MiddleRight@2x.png b/platform/icons/src/diff/compare4MiddleRight@2x.png new file mode 100644 index 000000000000..b36982e33b2d Binary files /dev/null and b/platform/icons/src/diff/compare4MiddleRight@2x.png differ diff --git a/platform/icons/src/diff/compare4RightBottom.png b/platform/icons/src/diff/compare4RightBottom.png new file mode 100644 index 000000000000..bd460441f4d2 Binary files /dev/null and b/platform/icons/src/diff/compare4RightBottom.png differ diff --git a/platform/icons/src/diff/compare4RightBottom@2x.png b/platform/icons/src/diff/compare4RightBottom@2x.png new file mode 100644 index 000000000000..e9610fed405a Binary files /dev/null and b/platform/icons/src/diff/compare4RightBottom@2x.png differ diff --git a/platform/icons/src/diff_frame128.png b/platform/icons/src/diff_frame128.png index 7fe30c294739..dea2af2cd39f 100644 Binary files a/platform/icons/src/diff_frame128.png and b/platform/icons/src/diff_frame128.png differ diff --git a/platform/icons/src/diff_frame16.png b/platform/icons/src/diff_frame16.png deleted file mode 100644 index b86600dd917b..000000000000 Binary files a/platform/icons/src/diff_frame16.png and /dev/null differ diff --git a/platform/icons/src/diff_frame32.png b/platform/icons/src/diff_frame32.png index 65bb77966fd3..8f09468171a0 100644 Binary files a/platform/icons/src/diff_frame32.png and b/platform/icons/src/diff_frame32.png differ diff --git a/platform/icons/src/diff_frame64.png b/platform/icons/src/diff_frame64.png index faab388ebb6a..754e9907427a 100644 Binary files a/platform/icons/src/diff_frame64.png and b/platform/icons/src/diff_frame64.png differ diff --git a/platform/icons/src/fileTypes/diagram.png b/platform/icons/src/fileTypes/diagram.png index 01b6e160220c..ae84839beb9c 100644 Binary files a/platform/icons/src/fileTypes/diagram.png and b/platform/icons/src/fileTypes/diagram.png differ diff --git a/platform/icons/src/fileTypes/diagram@2x.png b/platform/icons/src/fileTypes/diagram@2x.png index 02405d127fd6..e3d3b90803bd 100644 Binary files a/platform/icons/src/fileTypes/diagram@2x.png and b/platform/icons/src/fileTypes/diagram@2x.png differ diff --git a/platform/icons/src/icon-robots.txt b/platform/icons/src/icon-robots.txt index e9a17d2af1c5..2445ec12391c 100644 --- a/platform/icons/src/icon-robots.txt +++ b/platform/icons/src/icon-robots.txt @@ -1 +1,2 @@ -skip: diff_frame* \ No newline at end of file +skip: diff_frame* +deprecated: diff/Diff.png \ No newline at end of file diff --git a/platform/icons/src/vcs/allRevisions.png b/platform/icons/src/vcs/allRevisions.png deleted file mode 100644 index 31b05446b772..000000000000 Binary files a/platform/icons/src/vcs/allRevisions.png and /dev/null differ diff --git a/platform/icons/src/vcs/allRevisions@2x.png b/platform/icons/src/vcs/allRevisions@2x.png deleted file mode 100644 index b18f7049c199..000000000000 Binary files a/platform/icons/src/vcs/allRevisions@2x.png and /dev/null differ diff --git a/platform/icons/src/vcs/allRevisions@2x_dark.png b/platform/icons/src/vcs/allRevisions@2x_dark.png deleted file mode 100644 index be153e359237..000000000000 Binary files a/platform/icons/src/vcs/allRevisions@2x_dark.png and /dev/null differ diff --git a/platform/icons/src/vcs/allRevisions_dark.png b/platform/icons/src/vcs/allRevisions_dark.png deleted file mode 100644 index 984870678bde..000000000000 Binary files a/platform/icons/src/vcs/allRevisions_dark.png and /dev/null differ diff --git a/platform/indexing-api/src/com/intellij/psi/stubs/SerializationManager.java b/platform/indexing-api/src/com/intellij/psi/stubs/SerializationManager.java index 24e766db456e..c6ccb97f3d24 100644 --- a/platform/indexing-api/src/com/intellij/psi/stubs/SerializationManager.java +++ b/platform/indexing-api/src/com/intellij/psi/stubs/SerializationManager.java @@ -20,10 +20,8 @@ package com.intellij.psi.stubs; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.extensions.Extensions; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.StubFileElementType; -import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -45,16 +43,8 @@ public abstract class SerializationManager { if (mySerializersLoaded) return; synchronized (this) { if (mySerializersLoaded) return; - for (StubElementTypeHolderEP holderEP : Extensions.getExtensions(StubElementTypeHolderEP.EP_NAME)) { - holderEP.initialize(); - } - IStubElementType.markStubInitializationComplete(); - final IElementType[] stubElementTypes = IElementType.enumerate(new IElementType.Predicate() { - @Override - public boolean matches(@NotNull final IElementType type) { - return type instanceof StubSerializer; - } - }); + IStubElementType.loadRegisteredStubElementTypes(); + final IElementType[] stubElementTypes = IElementType.enumerate(type -> type instanceof StubSerializer); for (IElementType type : stubElementTypes) { if (type instanceof StubFileElementType && StubFileElementType.DEFAULT_EXTERNAL_ID.equals(((StubFileElementType)type).getExternalId())) { diff --git a/platform/lang-api/src/com/intellij/execution/RunManager.java b/platform/lang-api/src/com/intellij/execution/RunManager.java deleted file mode 100644 index ad4ee230d1e1..000000000000 --- a/platform/lang-api/src/com/intellij/execution/RunManager.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright 2000-2014 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.execution; - -import com.intellij.execution.configurations.ConfigurationFactory; -import com.intellij.execution.configurations.ConfigurationType; -import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.execution.configurations.RunProfile; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Manages the list of run/debug configurations in a project. - * - * @author anna - * @see RunnerRegistry - * @see ExecutionManager - */ -public abstract class RunManager { - public static final String UNNAMED = "Unnamed"; - - public static RunManager getInstance(final Project project) { - return project.getComponent(RunManager.class); - } - - /** - * Returns the list of all registered configuration types. - * - * @return all registered configuration types. - */ - @NotNull - public abstract ConfigurationType[] getConfigurationFactories(); - - /** - * Returns the list of all configurations of a specified type. - * - * @param type a run configuration type. - * @return all configurations of the type, or an empty array if no configurations of the type are defined. - */ - @NotNull - @Deprecated - public abstract RunConfiguration[] getConfigurations(@NotNull ConfigurationType type); - - /** - * Returns the list of all configurations of a specified type. - * - * @param type a run configuration type. - * @return all configurations of the type, or an empty array if no configurations of the type are defined. - */ - @NotNull - public abstract List getConfigurationsList(@NotNull ConfigurationType type); - - /** - * Returns the list of {@link RunnerAndConfigurationSettings} for all configurations of a specified type. - * - * @param type a run configuration type. - * @return settings for all configurations of the type, or an empty array if no configurations of the type are defined. - */ - @NotNull - @Deprecated - public abstract RunnerAndConfigurationSettings[] getConfigurationSettings(@NotNull ConfigurationType type); - - /** - * Returns the list of {@link RunnerAndConfigurationSettings} for all configurations of a specified type. - * - * @param type a run configuration type. - * @return settings for all configurations of the type, or an empty array if no configurations of the type are defined. - */ - @NotNull - public abstract List getConfigurationSettingsList(@NotNull ConfigurationType type); - - /** - * Returns the list of all run configurations. - * - * @return the list of all run configurations. - */ - @NotNull - @Deprecated - public abstract RunConfiguration[] getAllConfigurations(); - - /** - * Returns the list of all run configurations. - * - * @return the list of all run configurations. - */ - @NotNull - public abstract List getAllConfigurationsList(); - - /** - * Returns the list of all run configurations settings. - * - * @return the list of all run configurations settings. - */ - @NotNull - public abstract List getAllSettings(); - - /** - * Returns the list of all temporary run configurations. - * - * @return the list of all temporary run configurations. - * @see RunnerAndConfigurationSettings#isTemporary() - */ - @NotNull - @Deprecated - public abstract RunConfiguration[] getTempConfigurations(); - - /** - * Returns the list of all temporary run configurations settings. - * - * @return the list of all temporary run configurations settings. - * @see RunnerAndConfigurationSettings#isTemporary() - */ - @NotNull - public abstract List getTempConfigurationsList(); - - /** - * Checks if the specified run configuration is temporary and will be deleted when the temporary configurations limit is exceeded. - * - * @return true if the configuration is temporary, false otherwise. - * @see RunnerAndConfigurationSettings#isTemporary() - */ - @Deprecated - public abstract boolean isTemporary(@NotNull RunConfiguration configuration); - - /** - * Saves the specified temporary run configuration and makes it a permanent one. - * - * @param configuration the temporary run configuration to save. - */ - @Deprecated - public abstract void makeStable(@NotNull RunConfiguration configuration); - - /** - * Saves the specified temporary run settings and makes it a permanent one. - * - * @param settings the temporary settings to save. - */ - public abstract void makeStable(@NotNull RunnerAndConfigurationSettings settings); - - /** - * Returns the selected item in the run/debug configurations combobox. - * - * @return the selected configuration, or null if no configuration is defined or selected. - */ - @Nullable - public abstract RunnerAndConfigurationSettings getSelectedConfiguration(); - - /** - * Selects a configuration in the run/debug configurations combobox. - * - * @param configuration the configuration to select, or null if nothing should be selected. - */ - public abstract void setSelectedConfiguration(@Nullable RunnerAndConfigurationSettings configuration); - - /** - * Creates a configuration of the specified type with the specified name. Note that you need to call - * {@link #addConfiguration(RunnerAndConfigurationSettings, boolean)} if you want the configuration to be persisted in the project. - * - * @param name the name of the configuration to create (should be unique and not equal to any other existing configuration) - * @param factory the factory instance. - * @return the configuration settings object. - * @see RunManager#suggestUniqueName(String, Collection) - */ - @NotNull - public abstract RunnerAndConfigurationSettings createRunConfiguration(@NotNull String name, @NotNull ConfigurationFactory factory); - - /** - * Creates a configuration settings object based on a specified {@link RunConfiguration}. Note that you need to call - * {@link #addConfiguration(RunnerAndConfigurationSettings, boolean)} if you want the configuration to be persisted in the project. - * - * @param runConfiguration the run configuration - * @param factory the factory instance. - * @return the configuration settings object. - */ - @NotNull - public abstract RunnerAndConfigurationSettings createConfiguration(@NotNull RunConfiguration runConfiguration, @NotNull ConfigurationFactory factory); - - /** - * Returns the template settings for the specified configuration type. - * - * @param factory the configuration factory. - * @return the template settings. - */ - @NotNull - public abstract RunnerAndConfigurationSettings getConfigurationTemplate(ConfigurationFactory factory); - - /** - * Adds the specified run configuration to the list of run configurations stored in the project. - * - * @param settings the run configuration settings. - * @param isShared true if the configuration is marked as shared (stored in the versioned part of the project files), false if it's local - * (stored in the workspace file). - */ - public abstract void addConfiguration(final RunnerAndConfigurationSettings settings, final boolean isShared); - - /** - * Marks the specified run configuration as recently used (the temporary run configurations are deleted in LRU order). - * - * @param profile the run configuration to mark as recently used. - */ - public abstract void refreshUsagesList(RunProfile profile); - - @NotNull - public static String suggestUniqueName(@NotNull String str, @NotNull Collection currentNames) { - if (!currentNames.contains(str)) return str; - - final Matcher matcher = Pattern.compile("(.*?)\\s*\\(\\d+\\)").matcher(str); - final String originalName = (matcher.matches()) ? matcher.group(1) : str; - int i = 1; - while (true) { - final String newName = String.format("%s (%d)", originalName, i); - if (!currentNames.contains(newName)) return newName; - i++; - } - } - - public String suggestUniqueName(@Nullable String name, @Nullable ConfigurationType type) { - List settingsList = type != null ? getConfigurationSettingsList(type) : getAllSettings(); - List names = ContainerUtil.map(settingsList, settings -> settings.getName()); - return suggestUniqueName(StringUtil.notNullize(name, UNNAMED), names); - } - - /** - * Sets unique name if existing one is not 'unique' - * If settings type is not null (for example settings may be provided by plugin that is unavailable after IDE restart, so type would be suddenly null) - * name will be chosen unique for certain type otherwise name will be unique among all configurations - * @return {@code true} if name was changed - */ - public boolean setUniqueNameIfNeed(@NotNull RunnerAndConfigurationSettings settings) { - String oldName = settings.getName(); - settings.setName(suggestUniqueName(StringUtil.notNullize(oldName, UNNAMED), settings.getType())); - return !Comparing.equal(oldName, settings.getName()); - } - - /** - * Sets unique name if existing one is not 'unique' for corresponding configuration type - * @return {@code true} if name was changed - */ - public boolean setUniqueNameIfNeed(@NotNull RunConfiguration configuration) { - String oldName = configuration.getName(); - configuration.setName(suggestUniqueName(StringUtil.notNullize(oldName, UNNAMED), configuration.getType())); - return !Comparing.equal(oldName, configuration.getName()); - } -} diff --git a/platform/lang-api/src/com/intellij/execution/RunManager.kt b/platform/lang-api/src/com/intellij/execution/RunManager.kt new file mode 100644 index 000000000000..9ceec45d788b --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/RunManager.kt @@ -0,0 +1,200 @@ +/* + * Copyright 2000-2017 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.execution + +import com.intellij.execution.configurations.ConfigurationFactory +import com.intellij.execution.configurations.ConfigurationType +import com.intellij.execution.configurations.RunConfiguration +import com.intellij.execution.configurations.RunProfile +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.text.StringUtil +import com.intellij.util.text.nullize +import java.util.regex.Pattern + +/** + * Manages the list of run/debug configurations in a project. + * @see RunnerRegistry + * @see ExecutionManager + */ +abstract class RunManager { + companion object { + private val UNNAMED = "Unnamed" + + @JvmStatic + fun getInstance(project: Project): RunManager { + return project.getComponent(RunManager::class.java) + } + + @JvmStatic + fun suggestUniqueName(str: String, currentNames: Collection): String { + if (!currentNames.contains(str)) return str + + val matcher = Pattern.compile("(.*?)\\s*\\(\\d+\\)").matcher(str) + val originalName = if (matcher.matches()) matcher.group(1) else str + var i = 1 + while (true) { + val newName = String.format("%s (%d)", originalName, i) + if (!currentNames.contains(newName)) return newName + i++ + } + } + } + + /** + * Returns the list of all registered configuration types. + */ + abstract val configurationFactories: Array + + abstract val configurationFactoriesWithoutUnknown: List + + /** + * Returns the list of all configurations of a specified type. + * @param type a run configuration type. + * @return all configurations of the type, or an empty array if no configurations of the type are defined. + */ + @Deprecated("", ReplaceWith("getConfigurationsList(type)")) + fun getConfigurations(type: ConfigurationType) = getConfigurationsList(type).toTypedArray() + + /** + * Returns the list of all configurations of a specified type. + * @param type a run configuration type. + * @return all configurations of the type, or an empty array if no configurations of the type are defined. + */ + abstract fun getConfigurationsList(type: ConfigurationType): List + + /** + * Returns the list of [RunnerAndConfigurationSettings] for all configurations of a specified type. + * @param type a run configuration type. + * @return settings for all configurations of the type, or an empty array if no configurations of the type are defined. + */ + @Deprecated("", ReplaceWith("getConfigurationSettingsList(type)")) + fun getConfigurationSettings(type: ConfigurationType) = getConfigurationSettingsList(type).toTypedArray() + + /** + * Returns the list of [RunnerAndConfigurationSettings] for all configurations of a specified type. + * + * Template configuration is not included + * @param type a run configuration type. + * @return settings for all configurations of the type, or an empty array if no configurations of the type are defined. + */ + abstract fun getConfigurationSettingsList(type: ConfigurationType): List + + /** + * Returns the list of all run configurations. + */ + @Deprecated("", ReplaceWith("allConfigurationsList")) + fun getAllConfigurations() = allConfigurationsList.toTypedArray() + + /** + * Returns the list of all run configurations. + */ + abstract val allConfigurationsList: List + + /** + * Returns the list of all run configurations settings. + */ + abstract val allSettings: List + + /** + * Returns the list of all temporary run configurations settings. + * @see RunnerAndConfigurationSettings.isTemporary + */ + abstract val tempConfigurationsList: List + + /** + * Saves the specified temporary run settings and makes it a permanent one. + * @param settings the temporary settings to save. + */ + abstract fun makeStable(settings: RunnerAndConfigurationSettings) + + /** + * The selected item in the run/debug configurations combobox. + */ + abstract var selectedConfiguration: RunnerAndConfigurationSettings? + + /** + * Creates a configuration of the specified type with the specified name. Note that you need to call + * [.addConfiguration] if you want the configuration to be persisted in the project. + * @param name the name of the configuration to create (should be unique and not equal to any other existing configuration) + * @param factory the factory instance. + * @see RunManager.suggestUniqueName + */ + abstract fun createConfiguration(name: String, factory: ConfigurationFactory): RunnerAndConfigurationSettings + + fun createRunConfiguration(name: String, factory: ConfigurationFactory) = createConfiguration(name, factory) + + /** + * Creates a configuration settings object based on a specified [RunConfiguration]. Note that you need to call + * [.addConfiguration] if you want the configuration to be persisted in the project. + * @param runConfiguration the run configuration + * @param factory the factory instance. + */ + abstract fun createConfiguration(runConfiguration: RunConfiguration, factory: ConfigurationFactory): RunnerAndConfigurationSettings + + /** + * Returns the template settings for the specified configuration type. + * @param factory the configuration factory. + */ + abstract fun getConfigurationTemplate(factory: ConfigurationFactory): RunnerAndConfigurationSettings + + /** + * Adds the specified run configuration to the list of run configurations. + */ + abstract fun addConfiguration(settings: RunnerAndConfigurationSettings) + + /** + * Adds the specified run configuration to the list of run configurations stored in the project. + * @param settings the run configuration settings. + * @param isShared true if the configuration is marked as shared (stored in the versioned part of the project files), false if it's local + * * (stored in the workspace file). + */ + abstract fun addConfiguration(settings: RunnerAndConfigurationSettings, isShared: Boolean) + + /** + * Marks the specified run configuration as recently used (the temporary run configurations are deleted in LRU order). + * @param profile the run configuration to mark as recently used. + */ + abstract fun refreshUsagesList(profile: RunProfile) + + abstract fun hasSettings(settings: RunnerAndConfigurationSettings): Boolean + + fun suggestUniqueName(name: String?, type: ConfigurationType?): String { + val settingsList = if (type == null) allSettings else getConfigurationSettingsList(type) + return suggestUniqueName(name.nullize() ?: UNNAMED, settingsList.map { it.name }) + } + + /** + * Sets unique name if existing one is not 'unique' + * If settings type is not null (for example settings may be provided by plugin that is unavailable after IDE restart, so type would be suddenly null) + * name will be chosen unique for certain type otherwise name will be unique among all configurations + * @return `true` if name was changed + */ + fun setUniqueNameIfNeed(settings: RunnerAndConfigurationSettings): Boolean { + val oldName = settings.name + settings.name = suggestUniqueName(StringUtil.notNullize(oldName, UNNAMED), settings.type) + return oldName != settings.name + } + + /** + * Sets unique name if existing one is not 'unique' for corresponding configuration type + * @return `true` if name was changed + */ + fun setUniqueNameIfNeed(configuration: RunConfiguration): Boolean { + val oldName = configuration.name + configuration.name = suggestUniqueName(StringUtil.notNullize(oldName, UNNAMED), configuration.type) + return oldName != configuration.name + } +} diff --git a/platform/lang-api/src/com/intellij/execution/RunnerAndConfigurationSettings.java b/platform/lang-api/src/com/intellij/execution/RunnerAndConfigurationSettings.java index 2740cd0254aa..b64689c2ede4 100644 --- a/platform/lang-api/src/com/intellij/execution/RunnerAndConfigurationSettings.java +++ b/platform/lang-api/src/com/intellij/execution/RunnerAndConfigurationSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,20 +31,16 @@ import org.jetbrains.annotations.Nullable; public interface RunnerAndConfigurationSettings { /** * Returns the type of the run configuration. - * - * @return the type of the run configuration, or null if the settings object was loaded from disk and no plugin corresponding to the - * stored type of the run configuration is loaded. */ - @Nullable + @NotNull ConfigurationType getType(); /** * Returns the factory used to create the run configuration. * - * @return the factory, or null if the settings object was loaded from disk and no plugin corresponding to the stored type of the run - * configuration is loaded. + * @return the factory */ - @Nullable + @NotNull ConfigurationFactory getFactory(); /** @@ -62,20 +58,24 @@ public interface RunnerAndConfigurationSettings { */ boolean isTemporary(); + /** + * Is stored in the versioned part of the project files + */ + default boolean isShared() { + return false; + } + /** * Marks the configuration as temporary or permanent. * * @param temporary true if the configuration is temporary, false if it's permanent. - * @see RunManager#makeStable(com.intellij.execution.configurations.RunConfiguration) */ void setTemporary(boolean temporary); /** * Returns the {@link RunConfiguration} instance that will be used to execute this run configuration. - * - * @return the run configuration, or null if the settings object was loaded from disk and no plugin corresponding to the stored type - * of the run configuration is loaded. */ + @NotNull RunConfiguration getConfiguration(); /** @@ -90,6 +90,7 @@ public interface RunnerAndConfigurationSettings { * * @return the name of the configuration. */ + @NotNull String getName(); String getUniqueID(); @@ -121,7 +122,9 @@ public interface RunnerAndConfigurationSettings { * @throws RuntimeConfigurationError if the configuration settings contain a fatal problem which makes it impossible to execute the run * configuration. */ - void checkSettings() throws RuntimeConfigurationException; + default void checkSettings() throws RuntimeConfigurationException { + checkSettings(null); + } /** * Checks whether the run configuration settings are valid for execution with the specified executor. @@ -164,9 +167,9 @@ public interface RunnerAndConfigurationSettings { /** * Sets the "Before launch: Activate tool window" flag (for activation tool window Run/Debug etc.) * - * @param b if true, the tool window will be activated before launching this configuration. + * @param value if true, the tool window will be activated before launching this configuration. */ - void setActivateToolWindowBeforeRun(boolean activate); + void setActivateToolWindowBeforeRun(boolean value); /** * Returns the "Before launch: Activate tool window" flag (for activation tool window Run/Debug etc.) diff --git a/platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtensionBase.java b/platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtensionBase.java index 90512bb3f18e..ed5731cc41fc 100644 --- a/platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtensionBase.java +++ b/platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtensionBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -59,8 +59,7 @@ public abstract class RunConfigurationExtensionBase + + val configuration: RunConfiguration + + val runnerSettings: RunnerSettings? + + val configurationSettings: ConfigurationPerRunnerSettings? } \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/execution/configurations/LocatableConfigurationBase.java b/platform/lang-api/src/com/intellij/execution/configurations/LocatableConfigurationBase.java index 342d561f8aab..21c15b0f27bf 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/LocatableConfigurationBase.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/LocatableConfigurationBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -75,10 +75,6 @@ public abstract class LocatableConfigurationBase extends RunConfigurationBase im } } - @Override - public void checkConfiguration() throws RuntimeConfigurationException { - } - /** * Returns the text of the context menu action to start this run configuration. This can be different from the run configuration name * (for example, for a Java unit test method, the context menu shows just the name of the method, whereas the name of the run diff --git a/platform/lang-api/src/com/intellij/execution/configurations/ModuleBasedConfiguration.java b/platform/lang-api/src/com/intellij/execution/configurations/ModuleBasedConfiguration.java index 32af1f4dd8f6..df6201724102 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/ModuleBasedConfiguration.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/ModuleBasedConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -71,8 +71,10 @@ public abstract class ModuleBasedConfiguration getAllModules() { diff --git a/platform/lang-api/src/com/intellij/execution/configurations/RunConfiguration.java b/platform/lang-api/src/com/intellij/execution/configurations/RunConfiguration.java index b61d4d10b6d1..57299e47b8b6 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/RunConfiguration.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/RunConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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,14 +15,18 @@ */ package com.intellij.execution.configurations; +import com.intellij.execution.BeforeRunTask; import com.intellij.execution.runners.ProgramRunner; import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.JDOMExternalizable; +import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; +import java.util.List; + /** * Interface for run configurations which can be managed by a user and displayed in the UI. * @@ -35,16 +39,16 @@ import org.jetbrains.annotations.Nullable; * * @see RefactoringListenerProvider */ -public interface RunConfiguration extends RunProfile, JDOMExternalizable, Cloneable { +public interface RunConfiguration extends RunProfile, Cloneable { DataKey DATA_KEY = DataKey.create("runtimeConfiguration"); /** * Returns the type of the run configuration. - * - * @return the configuration type. */ @NotNull - ConfigurationType getType(); + default ConfigurationType getType() { + return getFactory().getType(); + } /** * Returns the factory that has created the run configuration. @@ -86,7 +90,9 @@ public interface RunConfiguration extends RunProfile, JDOMExternalizable, Clonea * @return the per-runner settings. */ @Nullable - ConfigurationPerRunnerSettings createRunnerSettings(ConfigurationInfoProvider provider); + default ConfigurationPerRunnerSettings createRunnerSettings(ConfigurationInfoProvider provider) { + return null; + } /** * Creates a UI control for editing the settings for a specific {@link ProgramRunner}. Can return null if the configuration has no @@ -96,7 +102,9 @@ public interface RunConfiguration extends RunProfile, JDOMExternalizable, Clonea * @return the editor for the per-runner settings. */ @Nullable - SettingsEditor getRunnerSettingsEditor(ProgramRunner runner); + default SettingsEditor getRunnerSettingsEditor(ProgramRunner runner) { + return null; + } /** * Clones the run configuration. @@ -111,7 +119,9 @@ public interface RunConfiguration extends RunProfile, JDOMExternalizable, Clonea * @return the unique ID of the configuration. */ @Deprecated - int getUniqueID(); + default int getUniqueID() { + return System.identityHashCode(this); + } /** * Checks whether the run configuration settings are valid. @@ -122,5 +132,20 @@ public interface RunConfiguration extends RunProfile, JDOMExternalizable, Clonea * @throws RuntimeConfigurationError if the configuration settings contain a fatal problem which makes it impossible * to execute the run configuration. */ - void checkConfiguration() throws RuntimeConfigurationException; + default void checkConfiguration() throws RuntimeConfigurationException { + } + + default void readExternal(Element element) { + } + + default void writeExternal(Element element) { + } + + @NotNull + default List getBeforeRunTasks() { + return Collections.emptyList(); + } + + default void setBeforeRunTasks(@NotNull List value) { + } } diff --git a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java index fa9e71b0e82e..f0afd43073a5 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -16,15 +16,16 @@ package com.intellij.execution.configurations; import com.intellij.diagnostic.logging.LogConsole; +import com.intellij.execution.BeforeRunTask; import com.intellij.execution.ExecutionTarget; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.runners.ProgramRunner; -import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizerUtil; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.util.SmartList; import com.intellij.util.xmlb.annotations.Attribute; import com.intellij.util.xmlb.annotations.Transient; import org.jdom.Element; @@ -33,6 +34,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * Standard base class for run configuration implementations. @@ -53,13 +56,15 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements private String myName = ""; private final Icon myIcon; - private ArrayList myLogFiles = new ArrayList<>(); - private ArrayList myPredefinedLogFiles = new ArrayList<>(); + private List myLogFiles = new SmartList<>(); + private List myPredefinedLogFiles = new SmartList<>(); private boolean mySaveOutput = false; private boolean myShowConsoleOnStdOut = false; private boolean myShowConsoleOnStdErr = false; private String myFileOutputPath = null; + private List myBeforeRunTasks = Collections.emptyList(); + protected RunConfigurationBase(@NotNull Project project, @NotNull ConfigurationFactory factory, final String name) { myProject = project; myFactory = factory; @@ -67,9 +72,14 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements myIcon = factory.getIcon(); } - @Override - public int getUniqueID() { - return System.identityHashCode(this); + @NotNull + @Transient + public List getBeforeRunTasks() { + return myBeforeRunTasks; + } + + public void setBeforeRunTasks(@NotNull List value) { + myBeforeRunTasks = value; } @Override @@ -88,12 +98,6 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements return myProject; } - @Override - @NotNull - public ConfigurationType getType() { - return myFactory.getType(); - } - @Override public Icon getIcon() { return myIcon; @@ -136,6 +140,8 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements runConfiguration.myShowConsoleOnStdOut = myShowConsoleOnStdOut; runConfiguration.myShowConsoleOnStdErr = myShowConsoleOnStdErr; copyCopyableDataTo(runConfiguration); + + myBeforeRunTasks = myBeforeRunTasks.isEmpty() ? Collections.emptyList() : new SmartList<>(myBeforeRunTasks); return runConfiguration; } @@ -148,11 +154,12 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements myPredefinedLogFiles.clear(); } - public void addPredefinedLogFile(PredefinedLogFile predefinedLogFile) { + public void addPredefinedLogFile(@NotNull PredefinedLogFile predefinedLogFile) { myPredefinedLogFiles.add(predefinedLogFile); } - public ArrayList getPredefinedLogFiles() { + @NotNull + public List getPredefinedLogFiles() { return myPredefinedLogFiles; } @@ -168,7 +175,8 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements return list; } - public ArrayList getLogFiles() { + @NotNull + public List getLogFiles() { return myLogFiles; } @@ -305,15 +313,4 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements public String toString() { return getType().getDisplayName() + ": " + getName(); } - - @SuppressWarnings("deprecation") - @Override - public ConfigurationPerRunnerSettings createRunnerSettings(ConfigurationInfoProvider provider) { - return null; - } - - @Override - public SettingsEditor getRunnerSettingsEditor(ProgramRunner runner) { - return null; - } } diff --git a/platform/lang-api/src/com/intellij/execution/configurations/RunProfileWithCompileBeforeLaunchOption.java b/platform/lang-api/src/com/intellij/execution/configurations/RunProfileWithCompileBeforeLaunchOption.java index c3842a97725f..28c171279c45 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/RunProfileWithCompileBeforeLaunchOption.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/RunProfileWithCompileBeforeLaunchOption.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -29,5 +29,7 @@ public interface RunProfileWithCompileBeforeLaunchOption extends RunProfile { * @return modules to compile before run. Empty list to build project */ @NotNull - Module[] getModules(); + default Module[] getModules() { + return Module.EMPTY_ARRAY; + } } \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/execution/configurations/RuntimeConfiguration.java b/platform/lang-api/src/com/intellij/execution/configurations/RuntimeConfiguration.java index 398415ab4d49..777e3e3e1da1 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/RuntimeConfiguration.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/RuntimeConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -16,9 +16,7 @@ package com.intellij.execution.configurations; -import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -29,12 +27,6 @@ public abstract class RuntimeConfiguration extends LocatableConfigurationBase im super(project, factory, name); } - @Override - @NotNull - public Module[] getModules() { - return Module.EMPTY_ARRAY; - } - @Override public RuntimeConfiguration clone() { return (RuntimeConfiguration)super.clone(); diff --git a/platform/lang-api/src/com/intellij/execution/configurations/UnknownConfigurationType.java b/platform/lang-api/src/com/intellij/execution/configurations/UnknownConfigurationType.java index 77507362b63f..a580a1508557 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/UnknownConfigurationType.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/UnknownConfigurationType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.execution.configurations; import com.intellij.icons.AllIcons; @@ -26,11 +25,22 @@ import javax.swing.*; * @author spleaner */ public class UnknownConfigurationType implements ConfigurationType { - public static final UnknownConfigurationType INSTANCE = new UnknownConfigurationType(); public static final String NAME = "Unknown"; + public static final ConfigurationFactory FACTORY = new ConfigurationFactory(new UnknownConfigurationType()) { + @Override + public RunConfiguration createTemplateConfiguration(@NotNull Project project) { + return new UnknownRunConfiguration(this, project); + } + + @Override + public boolean canConfigurationBeSingleton() { + return false; + } + }; + @Override public String getDisplayName() { return getId(); @@ -54,16 +64,6 @@ public class UnknownConfigurationType implements ConfigurationType { @Override public ConfigurationFactory[] getConfigurationFactories() { - return new ConfigurationFactory[] {new ConfigurationFactory(new UnknownConfigurationType()) { - @Override - public RunConfiguration createTemplateConfiguration(final Project project) { - return new UnknownRunConfiguration(this, project); - } - - @Override - public boolean canConfigurationBeSingleton() { - return false; - } - }}; + return new ConfigurationFactory[] {FACTORY}; } } diff --git a/platform/lang-api/src/com/intellij/execution/configurations/UnknownRunConfiguration.java b/platform/lang-api/src/com/intellij/execution/configurations/UnknownRunConfiguration.java index 583e84065410..55c9a96827c7 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/UnknownRunConfiguration.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/UnknownRunConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -13,13 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.execution.configurations; import com.intellij.execution.ExecutionException; import com.intellij.execution.Executor; import com.intellij.execution.runners.ExecutionEnvironment; -import com.intellij.execution.runners.ProgramRunner; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; @@ -31,7 +29,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** @@ -86,38 +83,16 @@ public class UnknownRunConfiguration implements RunConfiguration, WithoutOwnBefo return myProject; } - @Override - @NotNull - public ConfigurationType getType() { - return UnknownConfigurationType.INSTANCE; - } - - @Override - public ConfigurationPerRunnerSettings createRunnerSettings(final ConfigurationInfoProvider provider) { - return null; - } - - @Override - public SettingsEditor getRunnerSettingsEditor(final ProgramRunner runner) { - return null; - } - @Override public RunConfiguration clone() { try { - final UnknownRunConfiguration cloned = (UnknownRunConfiguration) super.clone(); - return cloned; - } catch (CloneNotSupportedException e) { + return (UnknownRunConfiguration)super.clone(); + } + catch (CloneNotSupportedException e) { return null; } } - - @Override - public int getUniqueID() { - return System.identityHashCode(this); - } - @Override public RunProfileState getState(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env) throws ExecutionException { String factoryName = ""; @@ -143,22 +118,18 @@ public class UnknownRunConfiguration implements RunConfiguration, WithoutOwnBefo @Override public void readExternal(final Element element) throws InvalidDataException { - myStoredElement = (Element) element.clone(); + myStoredElement = element.clone(); } @Override public void writeExternal(final Element element) throws WriteExternalException { if (myStoredElement != null) { - final List attributeList = myStoredElement.getAttributes(); - for (Object anAttributeList : attributeList) { - final Attribute a = (Attribute) anAttributeList; + for (Attribute a : myStoredElement.getAttributes()) { element.setAttribute(a.getName(), a.getValue()); } - final List list = myStoredElement.getChildren(); - for (Object child : list) { - final Element c = (Element) child; - element.addContent((Element) c.clone()); + for (Element child : myStoredElement.getChildren()) { + element.addContent(child.clone()); } } } @@ -170,7 +141,7 @@ public class UnknownRunConfiguration implements RunConfiguration, WithoutOwnBefo myPanel = new JPanel(); myPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 50, 0)); - myPanel.add(new JLabel("This configuration cannot be edited", JLabel.CENTER)); + myPanel.add(new JLabel("This configuration cannot be edited", SwingConstants.CENTER)); } @Override diff --git a/platform/lang-api/src/com/intellij/execution/junit/RuntimeConfigurationProducer.java b/platform/lang-api/src/com/intellij/execution/junit/RuntimeConfigurationProducer.java index 3d0e08812b1b..a43e6f5766fc 100644 --- a/platform/lang-api/src/com/intellij/execution/junit/RuntimeConfigurationProducer.java +++ b/platform/lang-api/src/com/intellij/execution/junit/RuntimeConfigurationProducer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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,7 +22,6 @@ import com.intellij.execution.configurations.*; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.module.Module; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.InvalidDataException; @@ -229,11 +228,5 @@ public abstract class RuntimeConfigurationProducer implements Comparable, Clonea public T getPeer() { return myConfig; } - - @Override - @NotNull - public Module[] getModules() { - return Module.EMPTY_ARRAY; - } } } diff --git a/platform/lang-api/src/com/intellij/lang/surroundWith/Surrounder.java b/platform/lang-api/src/com/intellij/lang/surroundWith/Surrounder.java index 0020ab937d30..0cbd1ae3ad06 100644 --- a/platform/lang-api/src/com/intellij/lang/surroundWith/Surrounder.java +++ b/platform/lang-api/src/com/intellij/lang/surroundWith/Surrounder.java @@ -19,6 +19,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; +import com.intellij.util.ArrayFactory; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,6 +31,9 @@ import org.jetbrains.annotations.Nullable; * @see SurroundDescriptor */ public interface Surrounder { + Surrounder[] EMPTY_ARRAY = new Surrounder[0]; + ArrayFactory myArrayFactory = count -> count == 0 ? EMPTY_ARRAY : new Surrounder[count]; + /** * Returns the user-visible name of the Surround With template. * diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java index da0fafd28bf2..b1dee8099214 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -269,7 +269,8 @@ public class CodeStyleSettings extends CommonCodeStyleSettings implements Clonea public boolean LAYOUT_STATIC_IMPORTS_SEPARATELY = true; public boolean USE_FQ_CLASS_NAMES; - + + /** @deprecated use com.intellij.psi.codeStyle.JavaCodeStyleSettings.CLASS_NAMES_IN_JAVADOC */ @Deprecated public boolean USE_FQ_CLASS_NAMES_IN_JAVADOC = true; public boolean USE_SINGLE_CLASS_IMPORTS = true; diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java index ffb1634077cf..54dba1d0da33 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java @@ -197,6 +197,7 @@ public interface CodeStyleSettingsCustomizable { CATCH_ON_NEW_LINE, FINALLY_ON_NEW_LINE, INDENT_CASE_FROM_SWITCH, + CASE_STATEMENT_ON_NEW_LINE, SPECIAL_ELSE_IF_TREATMENT, ENUM_CONSTANTS_WRAP, ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS, diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java index fd51fdcd66c1..947b0ddb863f 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java @@ -388,6 +388,8 @@ public class CommonCodeStyleSettings { public boolean FINALLY_ON_NEW_LINE = false; public boolean INDENT_CASE_FROM_SWITCH = true; + + public boolean CASE_STATEMENT_ON_NEW_LINE = true; /** * Controls "break" position relative to "case". diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/presentation/CodeStyleSettingPresentation.java b/platform/lang-api/src/com/intellij/psi/codeStyle/presentation/CodeStyleSettingPresentation.java index a7a032b3586f..8ba7302051a8 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/presentation/CodeStyleSettingPresentation.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/presentation/CodeStyleSettingPresentation.java @@ -411,7 +411,8 @@ public class CodeStyleSettingPresentation { result.put(new SettingsGroup(WRAPPING_SWITCH_STATEMENT), ContainerUtil.immutableList( new CodeStyleSettingPresentation("INDENT_CASE_FROM_SWITCH", ApplicationBundle.message("wrapping.indent.case.from.switch")), - new CodeStyleSettingPresentation("INDENT_BREAK_FROM_CASE", ApplicationBundle.message("wrapping.indent.break.from.case")) + new CodeStyleSettingPresentation("INDENT_BREAK_FROM_CASE", ApplicationBundle.message("wrapping.indent.break.from.case")), + new CodeStyleSettingPresentation("CASE_STATEMENT_ON_NEW_LINE", ApplicationBundle.message("wrapping.case.statements.on.one.line")) )); putGroupTop(result, "RESOURCE_LIST_WRAP", WRAPPING_TRY_RESOURCE_LIST, WRAP_VALUES, WRAP_OPTIONS); diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontDescriptionPanel.java b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontDescriptionPanel.java index 16c1462e75e6..20586a1d3570 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontDescriptionPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontDescriptionPanel.java @@ -193,13 +193,10 @@ public class ColorAndFontDescriptionPanel extends JPanel implements OptionsPanel updateColorChooser(myCbEffects, myEffectsColorChooser, description.isEffectsColorEnabled(), description.isEffectsColorChecked(), description.getEffectColor()); - if (description.isEffectsColorEnabled() && description.isEffectsColorChecked()) { - myEffectsCombo.setEnabled(description.isEditable()); - myEffectsModel.setEffectName(ContainerUtil.reverseMap(myEffectsMap).get(effectType)); - } - else { - myEffectsCombo.setEnabled(false); - } + String name = ContainerUtil.reverseMap(myEffectsMap).get(effectType); + myEffectsCombo.setSelectedItem(name); + myEffectsCombo + .setEnabled((description.isEffectsColorEnabled() && description.isEffectsColorChecked()) && description.isEditable()); setInheritanceInfo(description); myLabelFont.setEnabled(myCbBold.isEnabled() || myCbItalic.isEnabled()); } @@ -310,15 +307,5 @@ public class ColorAndFontDescriptionPanel extends JPanel implements OptionsPanel public EffectsComboModel(List names) { super(names); } - - /** - * Set the current effect name when a text attribute selection changes without notifying the listeners since otherwise it will - * be considered as an actual change and lead to unnecessary evens including 'read-only scheme' check. - * - * @param effectName - */ - public void setEffectName(@NotNull String effectName) { - mySelection = effectName; - } } } diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java index 7abc51bb7456..dbea5da7dd00 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java @@ -27,6 +27,8 @@ import com.intellij.ide.ui.laf.darcula.DarculaInstaller; import com.intellij.ide.ui.laf.darcula.DarculaLookAndFeelInfo; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.editor.colors.*; @@ -40,6 +42,7 @@ import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SchemeManager; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.options.colors.*; +import com.intellij.openapi.options.ex.Settings; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.DialogWrapper; @@ -71,6 +74,7 @@ import javax.swing.*; import java.awt.*; import java.util.*; import java.util.List; +import java.util.function.Function; public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract implements EditorOptionsProvider, SchemesModel { @@ -1401,4 +1405,24 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract return "Color And Fonts for "+getDisplayName(); } } + + public static Runnable getColorSelector(DataProvider provider, String search, String name) { + return getSelector(Settings.KEY.getData(provider), search, options -> options.findSubConfigurable(name)); + } + + public static Runnable getColorSelector(DataContext context, String search, Class type) { + return getSelector(Settings.KEY.getData(context), search, options -> options.findSubConfigurable(type)); + } + + private static Runnable getSelector(Settings settings, String search, Function function) { + if (settings == null) return null; + + ColorAndFontOptions options = settings.find(ColorAndFontOptions.class); + if (options == null) return null; + + SearchableConfigurable page = function.apply(options); + if (page == null) return null; + + return () -> settings.select(page, search); + } } diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/JumpToColorsAndFontsAction.java b/platform/lang-impl/src/com/intellij/application/options/colors/JumpToColorsAndFontsAction.java index 047f24a8286e..d33363b579f5 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/JumpToColorsAndFontsAction.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/JumpToColorsAndFontsAction.java @@ -36,16 +36,13 @@ import com.intellij.openapi.editor.markup.EffectType; import com.intellij.openapi.editor.markup.MarkupModel; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileTypes.SyntaxHighlighter; -import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.options.colors.AttributesDescriptor; import com.intellij.openapi.options.colors.ColorSettingsPage; import com.intellij.openapi.options.colors.ColorSettingsPages; -import com.intellij.openapi.options.ex.Settings; import com.intellij.openapi.options.newEditor.SettingsDialog; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; @@ -65,6 +62,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import static com.intellij.application.options.colors.ColorAndFontOptions.getColorSelector; import static com.intellij.ui.SimpleTextAttributes.*; /** @@ -189,13 +187,9 @@ public class JumpToColorsAndFontsAction extends DumbAwareAction { private static boolean openSettingsAndSelectKey(@NotNull Project project, @NotNull ColorSettingsPage page, @NotNull AttributesDescriptor descriptor) { SettingsDialog dialog = (SettingsDialog)ShowSettingsUtilImpl.getDialog( project, ShowSettingsUtilImpl.getConfigurableGroups(project, true), null); - Settings settings = Settings.KEY.getData(dialog); - ColorAndFontOptions configurable0 = settings == null ? null : settings.find(ColorAndFontOptions.class); - SearchableConfigurable configurable = configurable0 == null ? null : configurable0.findSubConfigurable(page.getDisplayName()); - if (configurable == null) return false; - Runnable runnable = configurable.enableSearch(descriptor.getDisplayName()); - ActionCallback callback = settings.select(configurable); - if (runnable != null) callback.doWhenDone(runnable); + Runnable selector = getColorSelector(dialog, descriptor.getDisplayName(), page.getDisplayName()); + if (selector == null) return false; + selector.run(); dialog.show(); return true; } diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/BaseCodeFoldingOptionsProvider.java b/platform/lang-impl/src/com/intellij/application/options/editor/BaseCodeFoldingOptionsProvider.java index 393e6cd0060c..708cd171366e 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/BaseCodeFoldingOptionsProvider.java +++ b/platform/lang-impl/src/com/intellij/application/options/editor/BaseCodeFoldingOptionsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -16,9 +16,9 @@ package com.intellij.application.options.editor; -import com.intellij.openapi.options.BeanConfigurable; -import com.intellij.openapi.application.ApplicationBundle; import com.intellij.codeInsight.folding.CodeFoldingSettings; +import com.intellij.openapi.application.ApplicationBundle; +import com.intellij.openapi.options.BeanConfigurable; /** * @author yole diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/CodeFoldingConfigurable.java b/platform/lang-impl/src/com/intellij/application/options/editor/CodeFoldingConfigurable.java index d996694fb11c..8dd413731568 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/CodeFoldingConfigurable.java +++ b/platform/lang-impl/src/com/intellij/application/options/editor/CodeFoldingConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -27,13 +27,11 @@ import com.intellij.openapi.options.CompositeConfigurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.ex.ConfigurableWrapper; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; -import java.util.ArrayList; import java.util.List; /** @@ -77,26 +75,15 @@ public class CodeFoldingConfigurable extends CompositeConfigurable> toUpdate = new ArrayList<>(); - for (final Editor editor : EditorFactory.getInstance().getAllEditors()) { - final Project project = editor.getProject(); - if (project != null && !project.isDefault()) { - toUpdate.add(Pair.create(editor, project)); - } - } + ApplicationManager.getApplication().invokeLater(() -> applyCodeFoldingSettingsChanges(), ModalityState.NON_MODAL); + } - ApplicationManager.getApplication().invokeLater(() -> { - for (Pair each : toUpdate) { - if (each.second == null || each.second.isDisposed()) { - continue; - } - final CodeFoldingManager foldingManager = CodeFoldingManager.getInstance(each.second); - if (foldingManager != null) { - foldingManager.buildInitialFoldings(each.first); - } - } - EditorOptionsPanel.reinitAllEditors(); - }, ModalityState.NON_MODAL); + public static void applyCodeFoldingSettingsChanges() { + EditorOptionsPanel.reinitAllEditors(); + for (Editor editor : EditorFactory.getInstance().getAllEditors()) { + Project project = editor.getProject(); + if (project != null) CodeFoldingManager.getInstance(project).scheduleAsyncFoldingUpdate(editor); + } } @Override diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorAppearanceConfigurable.form b/platform/lang-impl/src/com/intellij/application/options/editor/EditorAppearanceConfigurable.form index 8612fe9b06ca..ce1ba96531e9 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorAppearanceConfigurable.form +++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorAppearanceConfigurable.form @@ -1,16 +1,16 @@ - + - + - + @@ -86,7 +86,7 @@ - + @@ -140,18 +140,10 @@ - - - - - - - - - + diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorAppearanceConfigurable.java b/platform/lang-impl/src/com/intellij/application/options/editor/EditorAppearanceConfigurable.java index 86da19a416b6..655e9302f11a 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorAppearanceConfigurable.java +++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorAppearanceConfigurable.java @@ -64,7 +64,6 @@ public class EditorAppearanceConfigurable extends CompositeConfigurablenull. + */ + @Nullable + public abstract Boolean isCollapsedByDefault(@NotNull FoldRegion region); + + /** + * Schedules recalculation of foldings in editor ({@link com.intellij.codeInsight.daemon.impl.CodeFoldingPass CodeFoldingPass}), which + * will happen even if document (and other dependencies declared by {@link com.intellij.lang.folding.FoldingBuilder FoldingBuilder}) + * haven't changed. + */ + public abstract void scheduleAsyncFoldingUpdate(@NotNull Editor editor); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java index 751fcfa3ebdd..6ab6440cf372 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight.folding.impl; +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.folding.CodeFoldingManager; import com.intellij.codeInsight.hint.EditorFragmentComponent; import com.intellij.codeInsight.hint.HintManager; @@ -35,7 +36,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.*; import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.ui.LightweightHint; import com.intellij.util.containers.WeakList; @@ -230,6 +230,18 @@ public class CodeFoldingManagerImpl extends CodeFoldingManager implements Projec }; } + @Nullable + @Override + public Boolean isCollapsedByDefault(@NotNull FoldRegion region) { + return region.getUserData(UpdateFoldRegionsOperation.COLLAPSED_BY_DEFAULT); + } + + @Override + public void scheduleAsyncFoldingUpdate(@NotNull Editor editor) { + editor.putUserData(FoldingUpdate.CODE_FOLDING_KEY, null); + DaemonCodeAnalyzer.getInstance(myProject).restart(); + } + private void initFolding(@NotNull final Editor editor) { final Document document = editor.getDocument(); editor.getFoldingModel().runBatchFoldingOperation(() -> { @@ -286,12 +298,9 @@ public class CodeFoldingManagerImpl extends CodeFoldingManager implements Projec final FoldRegion[] regions = editor.getFoldingModel().getAllFoldRegions(); editor.getFoldingModel().runBatchFoldingOperation(() -> { - EditorFoldingInfo foldingInfo = EditorFoldingInfo.get(editor); for (FoldRegion region : regions) { - PsiElement element = foldingInfo.getPsiElement(region); - if (element != null) { - region.setExpanded(!FoldingPolicy.isCollapseByDefault(element)); - } + Boolean collapsedByDefault = region.getUserData(UpdateFoldRegionsOperation.COLLAPSED_BY_DEFAULT); + if (collapsedByDefault != null) region.setExpanded(!collapsedByDefault); } }); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/DocumentFoldingInfo.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/DocumentFoldingInfo.java index 940f57523c2c..b80172259557 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/DocumentFoldingInfo.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/DocumentFoldingInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -89,8 +89,8 @@ class DocumentFoldingInfo implements JDOMExternalizable, CodeFoldingState { if (!region.isValid()) continue; PsiElement element = info.getPsiElement(region); boolean expanded = region.isExpanded(); - boolean collapseByDefault = element != null && - FoldingPolicy.isCollapseByDefault(element) && + Boolean storedCollapseByDefault = region.getUserData(UpdateFoldRegionsOperation.COLLAPSED_BY_DEFAULT); + boolean collapseByDefault = storedCollapseByDefault != null && storedCollapseByDefault && !FoldingUtil.caretInsideRange(editor, TextRange.create(region)); if (collapseByDefault == expanded || element == null) { FoldingInfo fi = new FoldingInfo(region.getPlaceholderText(), expanded); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/FoldingUpdate.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/FoldingUpdate.java index 9cad7304052b..c5cc49e39745 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/FoldingUpdate.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/FoldingUpdate.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,6 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.FoldingModel; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; @@ -47,6 +46,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; import static com.intellij.codeInsight.folding.impl.UpdateFoldRegionsOperation.ApplyDefaultStateMode.EXCEPT_CARET_REGION; import static com.intellij.codeInsight.folding.impl.UpdateFoldRegionsOperation.ApplyDefaultStateMode.NO; @@ -54,7 +54,7 @@ import static com.intellij.codeInsight.folding.impl.UpdateFoldRegionsOperation.A public class FoldingUpdate { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.folding.impl.FoldingUpdate"); - private static final Key>> CODE_FOLDING_KEY = Key.create("code folding"); + static final Key> CODE_FOLDING_KEY = Key.create("code folding"); private static final Key CODE_FOLDING_FILE_EXTENSION_KEY = Key.create("code folding file extension"); private static final Comparator COMPARE_BY_OFFSET_REVERSED = (element, element1) -> { @@ -79,7 +79,7 @@ public class FoldingUpdate { currentFileExtension = virtualFile.getExtension(); } - ParameterizedCachedValue> value = editor.getUserData(CODE_FOLDING_KEY); + ParameterizedCachedValue value = editor.getUserData(CODE_FOLDING_KEY); if (value != null) { // There was a problem that old fold regions have been cached on file extension change (e.g. *.java -> *.groovy). // We want to drop them in such circumstances. @@ -91,15 +91,15 @@ public class FoldingUpdate { } editor.putUserData(CODE_FOLDING_FILE_EXTENSION_KEY, currentFileExtension); - if (value != null && value.hasUpToDateValue() && !applyDefaultState) return null; + if (value != null && value.hasUpToDateValue() && !applyDefaultState) return value.getValue(null); // param shouldn't matter, as the value is up-to-date if (quick) return getUpdateResult(file, document, true, project, editor, applyDefaultState).getValue(); return CachedValuesManager.getManager(project).getParameterizedCachedValue( editor, CODE_FOLDING_KEY, param -> { Document document1 = editor.getDocument(); PsiFile file1 = PsiDocumentManager.getInstance(project).getPsiFile(document1); - return getUpdateResult(file1, document1, param.first, project, editor, param.second); - }, false, Couple.of(false, applyDefaultState)); + return getUpdateResult(file1, document1, false, project, editor, param); + }, false, applyDefaultState); } private static CachedValueProvider.Result getUpdateResult(PsiFile file, @@ -113,12 +113,17 @@ public class FoldingUpdate { final UpdateFoldRegionsOperation operation = new UpdateFoldRegionsOperation(project, editor, file, elementsToFoldMap, applyDefaultState ? EXCEPT_CARET_REGION : NO, !applyDefaultState, false); - Runnable runnable = () -> editor.getFoldingModel().runBatchFoldingOperationDoNotCollapseCaret(operation); + AtomicBoolean alreadyExecuted = new AtomicBoolean(); + Runnable runnable = () -> { + if (alreadyExecuted.compareAndSet(false, true)) { + editor.getFoldingModel().runBatchFoldingOperationDoNotCollapseCaret(operation); + } + }; Set dependencies = new HashSet<>(); dependencies.add(document); dependencies.add(editor.getFoldingModel()); - for (FoldingDescriptor descriptor : elementsToFoldMap.values()) { - dependencies.addAll(descriptor.getDependencies()); + for (RegionInfo info : elementsToFoldMap.values()) { + dependencies.addAll(info.descriptor.getDependencies()); } return CachedValueProvider.Result.create(runnable, ArrayUtil.toObjectArray(dependencies)); } @@ -243,7 +248,8 @@ public class FoldingUpdate { diagnoseIncorrectRange(psi, document, language, foldingBuilder, descriptor, psiElement); continue; } - elementsToFoldMap.putValue(psiElement, descriptor); + RegionInfo regionInfo = new RegionInfo(descriptor, psiElement); + elementsToFoldMap.putValue(psiElement, regionInfo); } } } @@ -264,7 +270,7 @@ public class FoldingUpdate { : Attachment.EMPTY_ARRAY); } - static class FoldingMap extends MultiMap{ + static class FoldingMap extends MultiMap{ FoldingMap() { } @@ -274,14 +280,30 @@ public class FoldingUpdate { @NotNull @Override - protected Map> createMap() { + protected Map> createMap() { return new TreeMap<>(COMPARE_BY_OFFSET_REVERSED); } @NotNull @Override - protected Collection createCollection() { + protected Collection createCollection() { return new ArrayList<>(1); } } + + static class RegionInfo { + @NotNull + public final FoldingDescriptor descriptor; + public final boolean collapsedByDefault; + + private RegionInfo(@NotNull FoldingDescriptor descriptor, @NotNull PsiElement psiElement) { + this.descriptor = descriptor; + this.collapsedByDefault = FoldingPolicy.isCollapseByDefault(psiElement); + } + + @Override + public String toString() { + return descriptor + ", collapsedByDefault=" + collapsedByDefault; + } + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java index 26fede296b13..4b7d06069495 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -47,6 +47,7 @@ class UpdateFoldRegionsOperation implements Runnable { private static final Logger LOG = Logger.getInstance("#" + UpdateFoldRegionsOperation.class.getName()); private static final Key CAN_BE_REMOVED_WHEN_COLLAPSED = Key.create("canBeRemovedWhenCollapsed"); + static final Key COLLAPSED_BY_DEFAULT = Key.create("collapsedByDefault"); private final Project myProject; private final Editor myEditor; @@ -116,8 +117,9 @@ class UpdateFoldRegionsOperation implements Runnable { SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(myProject); for (PsiElement element : elementsToFold.keySet()) { ProgressManager.checkCanceled(); - final Collection descriptors = elementsToFold.get(element); - for (FoldingDescriptor descriptor : descriptors) { + final Collection descriptors = elementsToFold.get(element); + for (FoldingUpdate.RegionInfo regionInfo : descriptors) { + FoldingDescriptor descriptor = regionInfo.descriptor; FoldingGroup group = descriptor.getGroup(); TextRange range = descriptor.getRange(); String placeholder = null; @@ -145,11 +147,13 @@ class UpdateFoldRegionsOperation implements Runnable { } if (descriptor.canBeRemovedWhenCollapsed()) region.putUserData(CAN_BE_REMOVED_WHEN_COLLAPSED, Boolean.TRUE); + region.putUserData(COLLAPSED_BY_DEFAULT, regionInfo.collapsedByDefault); info.addRegion(region, smartPointerManager.createSmartPsiElementPointer(psi)); newRegions.add(region); - boolean expandStatus = !descriptor.isNonExpandable() && shouldExpandNewRegion(element, range, rangeToExpandStatusMap); + boolean expandStatus = !descriptor.isNonExpandable() && shouldExpandNewRegion(range, rangeToExpandStatusMap, + regionInfo.collapsedByDefault); if (group == null) { shouldExpand.put(region, expandStatus); } @@ -163,7 +167,9 @@ class UpdateFoldRegionsOperation implements Runnable { return newRegions; } - private boolean shouldExpandNewRegion(PsiElement element, TextRange range, Map rangeToExpandStatusMap) { + private boolean shouldExpandNewRegion(TextRange range, + Map rangeToExpandStatusMap, + boolean collapsedByDefault) { if (myApplyDefaultState != ApplyDefaultStateMode.NO) { // Considering that this code is executed only on initial fold regions construction on editor opening. if (myApplyDefaultState == ApplyDefaultStateMode.EXCEPT_CARET_REGION) { @@ -172,7 +178,7 @@ class UpdateFoldRegionsOperation implements Runnable { return true; } } - return !FoldingPolicy.isCollapseByDefault(element); + return !collapsedByDefault; } final Boolean oldStatus = rangeToExpandStatusMap.get(range); @@ -185,41 +191,48 @@ class UpdateFoldRegionsOperation implements Runnable { List toRemove = new ArrayList<>(); InjectedLanguageManager injectedManager = InjectedLanguageManager.getInstance(myProject); for (FoldRegion region : foldingModel.getAllFoldRegions()) { - if (myKeepCollapsedRegions && !region.isExpanded() && !regionOrGroupCanBeRemovedWhenCollapsed(region)) continue; - + boolean forceKeepRegion = myKeepCollapsedRegions && region.isValid() && !region.isExpanded() && + !regionOrGroupCanBeRemovedWhenCollapsed(region); + Boolean storedCollapsedByDefault = region.getUserData(COLLAPSED_BY_DEFAULT); PsiElement element = info.getPsiElement(region); if (element != null) { PsiFile containingFile = element.getContainingFile(); boolean isInjected = injectedManager.isInjectedFragment(containingFile); if (isInjected != myForInjected) continue; } - final Collection descriptors; - if (element != null && !(descriptors = elementsToFold.get(element)).isEmpty()) { + final Collection regionInfos; + if (element != null && !(regionInfos = elementsToFold.get(element)).isEmpty()) { boolean matchingDescriptorFound = false; - FoldingDescriptor[] array = descriptors.toArray(new FoldingDescriptor[descriptors.size()]); - for (FoldingDescriptor descriptor : array) { + FoldingUpdate.RegionInfo[] array = regionInfos.toArray(new FoldingUpdate.RegionInfo[regionInfos.size()]); + for (FoldingUpdate.RegionInfo regionInfo : array) { + FoldingDescriptor descriptor = regionInfo.descriptor; TextRange range = descriptor.getRange(); if (TextRange.areSegmentsEqual(region, range)) { matchingDescriptorFound = true; - if (!region.isValid() || + if (!forceKeepRegion && (!region.isValid() || region.getGroup() != null || descriptor.getGroup() != null || !region.getPlaceholderText().equals(descriptor.getPlaceholderText()) || - range.getLength() < 2 + range.getLength() < 2) ) { rangeToExpandStatusMap.put(range, region.isExpanded()); toRemove.add(region); break; } + else if (storedCollapsedByDefault != null && storedCollapsedByDefault != regionInfo.collapsedByDefault) { + rangeToExpandStatusMap.put(range, !regionInfo.collapsedByDefault); + toRemove.add(region); + break; + } else { - elementsToFold.remove(element, descriptor); + elementsToFold.remove(element, regionInfo); } } } - if (!matchingDescriptorFound) { + if (!matchingDescriptorFound && !forceKeepRegion) { if (Registry.is("editor.durable.folding.state")) { - for (FoldingDescriptor descriptor : descriptors) { - rangeToExpandStatusMap.put(descriptor.getRange(), region.isExpanded()); + for (FoldingUpdate.RegionInfo regionInfo : regionInfos) { + rangeToExpandStatusMap.put(regionInfo.descriptor.getRange(), region.isExpanded()); } } toRemove.add(region); @@ -229,7 +242,7 @@ class UpdateFoldRegionsOperation implements Runnable { boolean isExpanded = region.isExpanded(); rangeToExpandStatusMap.put(TextRange.create(region), isExpanded); } - else { + else if (!forceKeepRegion) { toRemove.add(region); } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/actions/ExpandAllRegionsAction.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/actions/ExpandAllRegionsAction.java index 488f1255d1c0..df550feac691 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/actions/ExpandAllRegionsAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/actions/ExpandAllRegionsAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,6 @@ package com.intellij.codeInsight.folding.impl.actions; import com.intellij.codeInsight.folding.CodeFoldingManager; -import com.intellij.codeInsight.folding.impl.EditorFoldingInfo; -import com.intellij.codeInsight.folding.impl.FoldingPolicy; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; @@ -26,7 +24,6 @@ import com.intellij.openapi.editor.FoldRegion; import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -39,15 +36,16 @@ public class ExpandAllRegionsAction extends EditorAction { Project project = editor.getProject(); assert project != null; PsiDocumentManager.getInstance(project).commitAllDocuments(); - CodeFoldingManager.getInstance(project).updateFoldRegions(editor); + CodeFoldingManager codeFoldingManager = CodeFoldingManager.getInstance(project); + codeFoldingManager.updateFoldRegions(editor); final List regions = getFoldRegionsForSelection(editor, caret); editor.getFoldingModel().runBatchFoldingOperation(() -> { boolean anythingDone = false; for (FoldRegion region : regions) { // try to restore to default state at first - PsiElement element = EditorFoldingInfo.get(editor).getPsiElement(region); - if (!region.isExpanded() && (element == null || !FoldingPolicy.isCollapseByDefault(element))) { + Boolean collapsedByDefault = codeFoldingManager.isCollapsedByDefault(region); + if (!region.isExpanded() && (collapsedByDefault == null || !collapsedByDefault)) { region.setExpanded(true); anythingDone = true; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlighter.java b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlighter.java index 746054ae90bf..4c7ff762cdb7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlighter.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlighter.java @@ -23,11 +23,10 @@ import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.editor.event.*; import com.intellij.openapi.editor.ex.DocumentEx; -import com.intellij.openapi.editor.ex.EditorEventMulticasterEx; -import com.intellij.openapi.editor.ex.FocusChangeListener; -import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManagerEvent; import com.intellij.openapi.fileEditor.FileEditorManagerListener; +import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupActivity; import com.intellij.openapi.util.TextRange; @@ -96,27 +95,20 @@ public class BraceHighlighter implements StartupActivity { }; eventMulticaster.addDocumentListener(documentListener, project); - final FocusChangeListener myFocusChangeListener = new FocusChangeListener() { - @Override - public void focusLost(Editor editor) { - clearBraces(editor); - } - - @Override - public void focusGained(Editor editor) { - updateBraces(editor, myAlarm); - } - }; - ((EditorEventMulticasterEx)eventMulticaster).addFocusChangeListner(myFocusChangeListener, project); - - final FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); - - fileEditorManager.addFileEditorManagerListener(new FileEditorManagerListener() { + project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerListener() { @Override public void selectionChanged(@NotNull FileEditorManagerEvent e) { myAlarm.cancelAllRequests(); + FileEditor oldEditor = e.getOldEditor(); + if (oldEditor instanceof TextEditor) { + clearBraces(((TextEditor)oldEditor).getEditor()); + } + FileEditor newEditor = e.getNewEditor(); + if (newEditor instanceof TextEditor) { + updateBraces(((TextEditor)newEditor).getEditor(), myAlarm); + } } - }, project); + }); } static void updateBraces(@NotNull final Editor editor, @NotNull final Alarm alarm) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java index fda551d2546b..85850d103124 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java @@ -567,6 +567,7 @@ public class BraceHighlightingHandler { hint.hide(); myEditor.putUserData(HINT_IN_EDITOR_KEY, null); } + removeLineMarkers(); } private void lineMarkFragment(int startLine, int endLine, @NotNull Color color) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/HighlightUsagesHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/HighlightUsagesHandler.java index 3150af69cbbb..e76cceecdc18 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/HighlightUsagesHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/HighlightUsagesHandler.java @@ -411,6 +411,7 @@ public class HighlightUsagesHandler extends HighlightHandlerBase { for (TextRange relativeRange : ReferenceRange.getRanges(ref)) { PsiElement element = ref.getElement(); TextRange range = safeCut(element.getTextRange(), relativeRange); + if (range.isEmpty()) continue; // injection occurs result.add(InjectedLanguageManager.getInstance(element.getProject()).injectedToHost(element, range)); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hints/HintUtils.kt b/platform/lang-impl/src/com/intellij/codeInsight/hints/HintUtils.kt index e2b5cf038d6e..9f89791d1e29 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hints/HintUtils.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/hints/HintUtils.kt @@ -17,14 +17,19 @@ package com.intellij.codeInsight.hints import com.intellij.codeInsight.hints.filtering.MatcherConstructor import com.intellij.lang.Language +import com.intellij.lang.LanguageExtensionPoint +import com.intellij.openapi.extensions.ExtensionPoint +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.util.text.StringUtil fun getHintProviders(): List> { - return Language.getRegisteredLanguages() - .filter { it.baseLanguage == null } + val name = ExtensionPointName>("com.intellij.codeInsight.parameterNameHints") + val languages = Extensions.getExtensions(name).map { it.language } + return languages + .mapNotNull { Language.findLanguageByID(it) } .map { it to InlayParameterHintsExtension.forLanguage(it) } - .filter { it.second != null } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionActionWithTextCaching.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionActionWithTextCaching.java index e32dc7d35791..ce2976ed221c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionActionWithTextCaching.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionActionWithTextCaching.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -122,7 +122,7 @@ public class IntentionActionWithTextCaching implements Comparable { private final IntentionAction myAction; private final BiConsumer myMarkInvoked; @@ -204,5 +204,18 @@ public class IntentionActionWithTextCaching implements Comparable { - final Runnable runnable = javaPage.enableSearch(toConfigure); - if (runnable != null) { - SwingUtilities.invokeLater(runnable); - } - }); + Runnable selector = ColorAndFontOptions.getColorSelector(dataContext, toConfigure, InspectionColorSettingsPage.class); + if (selector != null) { + selector.run(); } else { ColorAndFontOptions colorAndFontOptions = new ColorAndFontOptions(); diff --git a/platform/lang-impl/src/com/intellij/execution/RunManagerEx.java b/platform/lang-impl/src/com/intellij/execution/RunManagerEx.java index ec7dcaca93db..26f6ae17400f 100644 --- a/platform/lang-impl/src/com/intellij/execution/RunManagerEx.java +++ b/platform/lang-impl/src/com/intellij/execution/RunManagerEx.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,9 +15,9 @@ */ package com.intellij.execution; -import com.intellij.execution.configurations.ConfigurationFactory; import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.impl.RunnerAndConfigurationSettingsImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import org.jetbrains.annotations.NotNull; @@ -34,48 +34,53 @@ public abstract class RunManagerEx extends RunManager { return (RunManagerEx)project.getComponent(RunManager.class); } - //public abstract boolean isTemporary(@NotNull RunnerAndConfigurationSettings configuration); - /** - * @deprecated use {@link #setSelectedConfiguration(RunnerAndConfigurationSettings)} instead + * @deprecated Use {@link #setSelectedConfiguration(RunnerAndConfigurationSettings)} instead */ @Deprecated - public void setActiveConfiguration(@Nullable RunnerAndConfigurationSettings configuration) { + public final void setActiveConfiguration(@Nullable RunnerAndConfigurationSettings configuration) { setSelectedConfiguration(configuration); } public abstract void setTemporaryConfiguration(@Nullable RunnerAndConfigurationSettings tempConfiguration); + @NotNull public abstract RunManagerConfig getConfig(); - /** - * @deprecated use {@link RunManager#createRunConfiguration(String, ConfigurationFactory)} instead - * @param name - * @param type - * @return - */ - @NotNull - public abstract RunnerAndConfigurationSettings createConfiguration(String name, ConfigurationFactory type); + @Deprecated + public final void addConfiguration(RunnerAndConfigurationSettings settings, boolean isShared, List tasks, boolean addTemplateTasksIfAbsent) { + ((RunnerAndConfigurationSettingsImpl)settings).setShared(isShared); + addConfiguration(settings, tasks, addTemplateTasksIfAbsent); + } - public abstract void addConfiguration(RunnerAndConfigurationSettings settings, - boolean isShared, - List tasks, - boolean addTemplateTasksIfAbsent); + @Deprecated + public void addConfiguration(@NotNull RunnerAndConfigurationSettings settings, @NotNull List tasks, boolean addTemplateTasksIfAbsent) { + setBeforeRunTasks(settings.getConfiguration(), tasks, addTemplateTasksIfAbsent); + addConfiguration(settings); + } - public abstract boolean isConfigurationShared(RunnerAndConfigurationSettings settings); + @SuppressWarnings("MethodMayBeStatic") + @Deprecated + public final boolean isConfigurationShared(@NotNull RunnerAndConfigurationSettings settings) { + return settings.isShared(); + } @NotNull - public abstract List getBeforeRunTasks(RunConfiguration settings); + public abstract List getBeforeRunTasks(@NotNull RunConfiguration configuration); - public abstract void setBeforeRunTasks(RunConfiguration runConfiguration, List tasks, boolean addEnabledTemplateTasksIfAbsent); + public void setBeforeRunTasks(@NotNull RunConfiguration configuration, @NotNull List tasks) { + setBeforeRunTasks(configuration, tasks, false); + } + + public abstract void setBeforeRunTasks(@NotNull RunConfiguration configuration, @NotNull List tasks, boolean addEnabledTemplateTasksIfAbsent); @NotNull - public abstract List getBeforeRunTasks(@NotNull RunConfiguration settings, Key taskProviderID); + public abstract List getBeforeRunTasks(@NotNull RunConfiguration settings, Key taskProviderId); @NotNull - public abstract List getBeforeRunTasks(Key taskProviderID); + public abstract List getBeforeRunTasks(Key taskProviderId); - public abstract RunnerAndConfigurationSettings findConfigurationByName(@Nullable final String name); + public abstract RunnerAndConfigurationSettings findConfigurationByName(@Nullable String name); public Icon getConfigurationIcon(@NotNull RunnerAndConfigurationSettings settings) { return getConfigurationIcon(settings, false); @@ -83,13 +88,20 @@ public abstract class RunManagerEx extends RunManager { public abstract Icon getConfigurationIcon(@NotNull RunnerAndConfigurationSettings settings, boolean withLiveIndicator); + /** + * @deprecated Use {@link #getAllSettings()} + */ @NotNull - public abstract Collection getSortedConfigurations(); + @Deprecated + public final Collection getSortedConfigurations() { + return getAllSettings(); + } public abstract void removeConfiguration(@Nullable RunnerAndConfigurationSettings settings); - public abstract void addRunManagerListener(RunManagerListener listener); - public abstract void removeRunManagerListener(RunManagerListener listener); + public abstract void addRunManagerListener(@NotNull RunManagerListener listener); + + public abstract void removeRunManagerListener(@NotNull RunManagerListener listener); @NotNull public abstract Map> getStructure(@NotNull ConfigurationType type); diff --git a/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationPopup.java b/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationPopup.java index d0d02d9c2463..0ea7db645d6a 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationPopup.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationPopup.java @@ -18,7 +18,6 @@ package com.intellij.execution.actions; import com.intellij.execution.*; import com.intellij.execution.configurations.ConfigurationType; -import com.intellij.execution.configurations.UnknownConfigurationType; import com.intellij.execution.impl.EditConfigurationsDialog; import com.intellij.execution.impl.RunDialog; import com.intellij.execution.impl.RunnerAndConfigurationSettingsImpl; @@ -206,8 +205,7 @@ public class ChooseRunConfigurationPopup implements ExecutorProvider { } private static void deleteConfiguration(final Project project, @NotNull final RunnerAndConfigurationSettings configurationSettings) { - final RunManagerEx manager = RunManagerEx.getInstanceEx(project); - manager.removeConfiguration(configurationSettings); + RunManagerEx.getInstanceEx(project).removeConfiguration(configurationSettings); } @Override @@ -981,36 +979,34 @@ public class ChooseRunConfigurationPopup implements ExecutorProvider { } Map wrappedExisting = new LinkedHashMap<>(); - for (ConfigurationType type : manager.getConfigurationFactories()) { - if (!(type instanceof UnknownConfigurationType)) { - Map> structure = manager.getStructure(type); - for (Map.Entry> entry : structure.entrySet()) { - if (entry.getValue().isEmpty()) { - continue; - } + for (ConfigurationType type : manager.getConfigurationFactoriesWithoutUnknown()) { + Map> structure = manager.getStructure(type); + for (Map.Entry> entry : structure.entrySet()) { + if (entry.getValue().isEmpty()) { + continue; + } - final String key = entry.getKey(); - if (key != null) { - boolean isSelected = entry.getValue().contains(selectedConfiguration); - if (isSelected) { - assert selectedConfiguration != null; - } - FolderWrapper folderWrapper = new FolderWrapper(project, executorProvider, - key + (isSelected ? " (mnemonic is to \"" + selectedConfiguration.getName() + "\")" : ""), - entry.getValue()); - if (isSelected) { - folderWrapper.setMnemonic(1); - } - result.add(folderWrapper); + final String key = entry.getKey(); + if (key != null) { + boolean isSelected = entry.getValue().contains(selectedConfiguration); + if (isSelected) { + assert selectedConfiguration != null; } - else { - for (RunnerAndConfigurationSettings configuration : entry.getValue()) { - final ItemWrapper wrapped = ItemWrapper.wrap(project, configuration); - if (configuration == selectedConfiguration) { - wrapped.setMnemonic(1); - } - wrappedExisting.put(configuration, wrapped); + FolderWrapper folderWrapper = new FolderWrapper(project, executorProvider, + key + (isSelected ? " (mnemonic is to \"" + selectedConfiguration.getName() + "\")" : ""), + entry.getValue()); + if (isSelected) { + folderWrapper.setMnemonic(1); + } + result.add(folderWrapper); + } + else { + for (RunnerAndConfigurationSettings configuration : entry.getValue()) { + final ItemWrapper wrapped = ItemWrapper.wrap(project, configuration); + if (configuration == selectedConfiguration) { + wrapped.setMnemonic(1); } + wrappedExisting.put(configuration, wrapped); } } } diff --git a/platform/lang-impl/src/com/intellij/execution/actions/CreateAction.java b/platform/lang-impl/src/com/intellij/execution/actions/CreateAction.java index 0f499f4ae0f1..8af49fa43374 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/CreateAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/CreateAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -19,7 +19,6 @@ package com.intellij.execution.actions; import com.intellij.execution.ExecutionBundle; import com.intellij.execution.RunManager; import com.intellij.execution.RunnerAndConfigurationSettings; -import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.impl.RunDialog; import com.intellij.execution.impl.RunManagerImpl; import com.intellij.openapi.actionSystem.Presentation; @@ -122,14 +121,9 @@ public class CreateAction extends BaseRunConfigurationAction { @Override public void perform(final ConfigurationContext context) { - final RunManagerImpl runManager = (RunManagerImpl)context.getRunManager(); - final RunnerAndConfigurationSettings configuration = context.getConfiguration(); - final RunnerAndConfigurationSettings template = runManager.getConfigurationTemplate(configuration.getFactory()); - final RunConfiguration templateConfiguration = template.getConfiguration(); - runManager.addConfiguration(configuration, - runManager.isConfigurationShared(template), - runManager.getBeforeRunTasks(templateConfiguration), - false); + RunManagerImpl runManager = (RunManagerImpl)context.getRunManager(); + RunnerAndConfigurationSettings configuration = context.getConfiguration(); + runManager.addConfiguration(configuration, runManager.getConfigurationTemplate(configuration.getFactory()).isShared()); runManager.setSelectedConfiguration(configuration); } } @@ -146,9 +140,7 @@ public class CreateAction extends BaseRunConfigurationAction { final RunnerAndConfigurationSettings configuration = context.getConfiguration(); if (RunDialog.editConfiguration(context.getProject(), configuration, ExecutionBundle.message("create.run.configuration.for.item.dialog.title", configuration.getName()))) { final RunManagerImpl runManager = (RunManagerImpl)context.getRunManager(); - runManager.addConfiguration(configuration, - runManager.isConfigurationShared(configuration), - runManager.getBeforeRunTasks(configuration.getConfiguration()), false); + runManager.addConfiguration(configuration); runManager.setSelectedConfiguration(configuration); } } diff --git a/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java b/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java index 9aa82d25e178..0779bb86c6b4 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -30,12 +30,11 @@ import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.wm.ex.WindowManagerEx; -import com.intellij.openapi.wm.impl.IdeFrameImpl; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.SizedIcon; import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.util.IconUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.JBUI; import org.jetbrains.annotations.NotNull; @@ -43,7 +42,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -156,8 +154,7 @@ public class RunConfigurationsComboBoxAction extends ComboBoxAction implements D allActionsGroup.addSeparator(); } - final ConfigurationType[] types = runManager.getConfigurationFactories(); - for (ConfigurationType type : types) { + for (ConfigurationType type : runManager.getConfigurationFactories()) { final DefaultActionGroup actionGroup = new DefaultActionGroup(); Map> structure = runManager.getStructure(type); for (Map.Entry> entry : structure.entrySet()) { @@ -228,8 +225,7 @@ public class RunConfigurationsComboBoxAction extends ComboBoxAction implements D if (selectedConfiguration != null && selectedConfiguration.isTemporary()) { return selectedConfiguration; } - Iterator iterator = RunManager.getInstance(project).getTempConfigurationsList().iterator(); - return iterator.hasNext() ? iterator.next() : null; + return ContainerUtil.getFirstItem(RunManager.getInstance(project).getTempConfigurationsList()); } } @@ -273,7 +269,7 @@ public class RunConfigurationsComboBoxAction extends ComboBoxAction implements D myConfiguration = configuration; myProject = project; String name = configuration.getName(); - if (name == null || name.length() == 0) { + if (name.isEmpty()) { name = " "; } final Presentation presentation = getTemplatePresentation(); diff --git a/platform/lang-impl/src/com/intellij/execution/compound/CompoundRunConfigurationSettingsEditor.java b/platform/lang-impl/src/com/intellij/execution/compound/CompoundRunConfigurationSettingsEditor.java index 8be37648aa44..4fd3e3f1bd04 100644 --- a/platform/lang-impl/src/com/intellij/execution/compound/CompoundRunConfigurationSettingsEditor.java +++ b/platform/lang-impl/src/com/intellij/execution/compound/CompoundRunConfigurationSettingsEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -19,7 +19,6 @@ import com.intellij.execution.BeforeRunTask; import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.execution.configurations.UnknownConfigurationType; import com.intellij.execution.impl.RunConfigurationBeforeRunProvider; import com.intellij.execution.impl.RunConfigurationSelector; import com.intellij.execution.impl.RunManagerImpl; @@ -70,7 +69,7 @@ public class CompoundRunConfigurationSettingsEditor extends SettingsEditor tasks = myRunManager.getBeforeRunTasks(candidate); + List> tasks = myRunManager.getBeforeRunTasks(candidate); for (BeforeRunTask task : tasks) { if (task instanceof RunConfigurationBeforeRunProvider.RunConfigurableBeforeRunTask) { RunConfigurationBeforeRunProvider.RunConfigurableBeforeRunTask runTask @@ -119,13 +118,10 @@ public class CompoundRunConfigurationSettingsEditor extends SettingsEditor all = new ArrayList<>(); - for (ConfigurationType type : myRunManager.getConfigurationFactories()) { - if (!(type instanceof UnknownConfigurationType)) { - for (RunnerAndConfigurationSettings settings : myRunManager.getConfigurationSettingsList(type)) { - all.add(settings.getConfiguration()); - } + for (ConfigurationType type : myRunManager.getConfigurationFactoriesWithoutUnknown()) { + for (RunnerAndConfigurationSettings settings : myRunManager.getConfigurationSettingsList(type)) { + all.add(settings.getConfiguration()); } } diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/actions/CopyConfigurationAction.java b/platform/lang-impl/src/com/intellij/execution/dashboard/actions/CopyConfigurationAction.java index c977ec3aa7f6..a4a023889730 100644 --- a/platform/lang-impl/src/com/intellij/execution/dashboard/actions/CopyConfigurationAction.java +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/actions/CopyConfigurationAction.java @@ -49,8 +49,7 @@ public class CopyConfigurationAction extends RunConfigurationTreeAction { @Override protected boolean isEnabled4(DashboardRunConfigurationNode node) { - return RunManager.getInstance(node.getProject()).getAllConfigurationsList().contains( - node.getConfigurationSettings().getConfiguration()); + return RunManager.getInstance(node.getProject()).hasSettings(node.getConfigurationSettings()); } @Override @@ -68,10 +67,8 @@ public class CopyConfigurationAction extends RunConfigurationTreeAction { ((ConfigurationFactoryEx)factory).onConfigurationCopied(settings.getConfiguration()); } - if (RunDialog.editConfiguration(node.getProject(), copiedSettings, - ExecutionBundle.message("run.dashboard.edit.configuration.dialog.title"))) { - runManager.addConfiguration(copiedSettings, runManager.isConfigurationShared(settings), - runManager.getBeforeRunTasks(settings.getConfiguration()), false); + if (RunDialog.editConfiguration(node.getProject(), copiedSettings, ExecutionBundle.message("run.dashboard.edit.configuration.dialog.title"))) { + runManager.addConfiguration(copiedSettings, settings.isShared()); } } } diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/actions/EditConfigurationAction.java b/platform/lang-impl/src/com/intellij/execution/dashboard/actions/EditConfigurationAction.java index 1622456db19a..680652cb74bf 100644 --- a/platform/lang-impl/src/com/intellij/execution/dashboard/actions/EditConfigurationAction.java +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/actions/EditConfigurationAction.java @@ -41,8 +41,7 @@ public class EditConfigurationAction extends RunConfigurationTreeAction { @Override protected boolean isEnabled4(DashboardRunConfigurationNode node) { - return RunManager.getInstance(node.getProject()).getAllConfigurationsList().contains( - node.getConfigurationSettings().getConfiguration()); + return RunManager.getInstance(node.getProject()).hasSettings(node.getConfigurationSettings()); } @Override diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/actions/RemoveConfigurationAction.java b/platform/lang-impl/src/com/intellij/execution/dashboard/actions/RemoveConfigurationAction.java index d83295f0af97..3733e2f189be 100644 --- a/platform/lang-impl/src/com/intellij/execution/dashboard/actions/RemoveConfigurationAction.java +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/actions/RemoveConfigurationAction.java @@ -40,8 +40,7 @@ public class RemoveConfigurationAction extends RunConfigurationTreeAction { @Override protected boolean isEnabled4(DashboardRunConfigurationNode node) { - return RunManager.getInstance(node.getProject()).getAllConfigurationsList().contains( - node.getConfigurationSettings().getConfiguration()); + return RunManager.getInstance(node.getProject()).hasSettings(node.getConfigurationSettings()); } @Override diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/tree/RunConfigurationNode.java b/platform/lang-impl/src/com/intellij/execution/dashboard/tree/RunConfigurationNode.java index e0771d60f363..666c8a90067b 100644 --- a/platform/lang-impl/src/com/intellij/execution/dashboard/tree/RunConfigurationNode.java +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/tree/RunConfigurationNode.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -64,7 +64,7 @@ class RunConfigurationNode extends AbstractTreeNode extend private DefaultMutableTreeNode buildNodes() { DefaultMutableTreeNode root = new DefaultMutableTreeNode(new Descriptor()); RunManager runManager = RunManager.getInstance(myProject); - final ConfigurationType[] configTypes = runManager.getConfigurationFactories(); - - for (final ConfigurationType type : configTypes) { + for (final ConfigurationType type : runManager.getConfigurationFactories()) { final Icon icon = type.getIcon(); DefaultMutableTreeNode typeNode = new DefaultMutableTreeNode(new ConfigurationTypeDescriptor(type, icon, isConfigurationAssigned(type))); root.add(typeNode); @@ -225,10 +223,11 @@ public abstract class BaseExecuteBeforeRunDialog extend protected abstract boolean isRunning(T task); private void update(RunConfiguration config, boolean enabled, RunManagerImpl runManager) { - List tasks = runManager.getBeforeRunTasks(config); + List> tasks = runManager.getBeforeRunTasks(config); BeforeRunTaskProvider provider = BeforeRunTaskProvider.getProvider(myProject, getTaskID()); - if (provider == null) + if (provider == null) { return; + } T task = provider.createTask(config); update(task); task.setEnabled(true); @@ -366,6 +365,5 @@ public abstract class BaseExecuteBeforeRunDialog extend return this; } - } } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/BaseRCSettingsConfigurable.java b/platform/lang-impl/src/com/intellij/execution/impl/BaseRCSettingsConfigurable.java index f1ffbbc534a8..61794c698cc5 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/BaseRCSettingsConfigurable.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/BaseRCSettingsConfigurable.java @@ -38,15 +38,13 @@ abstract class BaseRCSettingsConfigurable extends SettingsEditorConfigurable tasks = RunManagerImpl.getInstanceImpl(configuration.getProject()).getBeforeRunTasks(configuration); + List> tasks = RunManagerImpl.getInstanceImpl(configuration.getProject()).getBeforeRunTasks(configuration); for (BeforeRunTask beforeRunTask : tasks) { if (beforeRunTask instanceof RunConfigurationBeforeRunProvider.RunConfigurableBeforeRunTask) { if (configurationSet.add(((RunConfigurationBeforeRunProvider.RunConfigurableBeforeRunTask)beforeRunTask).getSettings().getConfiguration())) diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java b/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java index 506639b0b95f..558d913b546b 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -126,7 +126,7 @@ public class ConfigurationSettingsEditorWrapper extends SettingsEditor settings != null && usesMyModule(settings.getConfiguration()); @NotNull private final RunManagerImpl myManager; - @Nullable - private List myUnloadedElements = null; public ModuleRunConfigurationManager(@NotNull final Module module, @NotNull final RunManagerImpl runManager) { myModule = module; @@ -63,11 +58,11 @@ public final class ModuleRunConfigurationManager implements PersistentStateCompo public void beforeModuleRemoved(@NotNull Project project, @NotNull Module module) { if (myModule.equals(module)) { LOG.debug("time to remove something from project (" + project + ")"); + Collection moduleRunConfigurations; synchronized (LOCK) { - for (final RunnerAndConfigurationSettings settings : getModuleRunConfigurationSettings()) { - myManager.removeConfiguration(settings); - } + moduleRunConfigurations = getModuleRunConfigurationSettings(); } + myManager.removeConfigurations(moduleRunConfigurations); } } }); @@ -99,7 +94,7 @@ public final class ModuleRunConfigurationManager implements PersistentStateCompo @NotNull private Collection getModuleRunConfigurationSettings() { - return ContainerUtil.filter(myManager.getConfigurationSettings(), myModuleConfigCondition); + return ContainerUtil.filter(myManager.getAllSettings(), myModuleConfigCondition); } private boolean usesMyModule(RunConfiguration config) { @@ -109,14 +104,7 @@ public final class ModuleRunConfigurationManager implements PersistentStateCompo public void writeExternal(@NotNull final Element element) throws WriteExternalException { LOG.debug("writeExternal(" + myModule + ")"); - for (final RunnerAndConfigurationSettings settings : getModuleRunConfigurationSettings()) { - myManager.addConfigurationElement(element, settings); - } - if (myUnloadedElements != null) { - for (final Element unloadedElement : myUnloadedElements) { - element.addContent(unloadedElement.clone()); - } - } + myManager.writeConfigurations(element, getModuleRunConfigurationSettings()); } public void readExternal(@NotNull final Element element) { @@ -127,33 +115,19 @@ public final class ModuleRunConfigurationManager implements PersistentStateCompo private void doReadExternal(@NotNull Element element) { LOG.debug("readExternal(" + myModule + ")"); - myUnloadedElements = null; - final Set existing = new HashSet<>(); + final Set existing = new SmartHashSet<>(); - for (final Element child : element.getChildren()) { - final RunnerAndConfigurationSettings configuration = myManager.loadConfiguration(child, true); - if (configuration == null && Comparing.strEqual(element.getName(), RunManagerImpl.CONFIGURATION)) { - if (myUnloadedElements == null) myUnloadedElements = new ArrayList<>(2); - myUnloadedElements.add(element); - } + for (final Element child : element.getChildren(RunManagerImpl.CONFIGURATION)) { + existing.add(myManager.loadConfiguration(child, true).getUniqueID()); + } - if (configuration != null) { - existing.add(configuration.getUniqueID()); + for (RunnerAndConfigurationSettings settings : myManager.getAllSettings()) { + if (!usesMyModule(settings.getConfiguration())) { + existing.add(settings.getUniqueID()); } } - for (final RunConfiguration configuration : myManager.getAllConfigurationsList()) { - if (!usesMyModule(configuration)) { - RunnerAndConfigurationSettings settings = myManager.getSettings(configuration); - if (settings != null) { - existing.add(settings.getUniqueID()); - } - } - } myManager.removeNotExistingSharedConfigurations(existing); - - // IDEA-60004: configs may never be sorted before write, so call it manually after shared configs read - myManager.setOrdered(false); - myManager.getSortedConfigurations(); + myManager.requestSort(); } } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ProjectRunConfigurationManager.java b/platform/lang-impl/src/com/intellij/execution/impl/ProjectRunConfigurationManager.java deleted file mode 100644 index da6e546a76ba..000000000000 --- a/platform/lang-impl/src/com/intellij/execution/impl/ProjectRunConfigurationManager.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.execution.impl; - -import com.intellij.execution.RunnerAndConfigurationSettings; -import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.execution.configurations.UnknownRunConfiguration; -import com.intellij.openapi.components.PersistentStateComponent; -import com.intellij.openapi.components.State; -import com.intellij.openapi.components.StateSplitterEx; -import com.intellij.openapi.components.Storage; -import com.intellij.openapi.util.Pair; -import com.intellij.util.SmartList; -import com.intellij.util.containers.ContainerUtil; -import gnu.trove.THashSet; -import org.jdom.Element; -import org.jetbrains.annotations.NotNull; - -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -@State(name = "ProjectRunConfigurationManager", storages = @Storage(value = "runConfigurations", stateSplitter = ProjectRunConfigurationManager.RunConfigurationStateSplitter.class)) -public class ProjectRunConfigurationManager implements PersistentStateComponent { - private final RunManagerImpl myManager; - private List myUnloadedElements; - - public ProjectRunConfigurationManager(@NotNull RunManagerImpl manager) { - myManager = manager; - } - - @Override - public Element getState() { - Element state = new Element("state"); - for (RunnerAndConfigurationSettings configuration : myManager.getStableConfigurations(true)) { - myManager.addConfigurationElement(state, configuration); - } - if (!ContainerUtil.isEmpty(myUnloadedElements)) { - for (Element unloadedElement : myUnloadedElements) { - state.addContent(unloadedElement.clone()); - } - } - return state; - } - - @Override - public void loadState(Element state) { - if (myUnloadedElements != null) { - myUnloadedElements.clear(); - } - - Set existing = new THashSet<>(); - for (Iterator iterator = state.getChildren().iterator(); iterator.hasNext(); ) { - Element child = iterator.next(); - RunnerAndConfigurationSettings configuration = myManager.loadConfiguration(child, true); - if (configuration != null) { - existing.add(configuration.getUniqueID()); - } - else if (child.getName().equals(RunManagerImpl.CONFIGURATION)) { - if (myUnloadedElements == null) { - myUnloadedElements = new SmartList<>(); - } - iterator.remove(); - myUnloadedElements.add(child); - } - } - - myManager.removeNotExistingSharedConfigurations(existing); - if (myManager.getSelectedConfiguration() == null) { - final List allConfigurations = myManager.getAllConfigurationsList(); - for (final RunConfiguration configuration : allConfigurations) { - final RunnerAndConfigurationSettings settings = myManager.getSettings(allConfigurations.get(0)); - if (!(configuration instanceof UnknownRunConfiguration)) { - myManager.setSelectedConfiguration(settings); - break; - } - } - } - - // IDEA-60004: configs may never be sorted before write, so call it manually after shared configs read - myManager.setOrdered(false); - myManager.getSortedConfigurations(); - } - - static class RunConfigurationStateSplitter extends StateSplitterEx { - @Override - public List> splitState(@NotNull Element state) { - return splitState(state, RunManagerImpl.NAME_ATTR); - } - } -} diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ProjectRunConfigurationManager.kt b/platform/lang-impl/src/com/intellij/execution/impl/ProjectRunConfigurationManager.kt new file mode 100644 index 000000000000..cb496d2922fd --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/impl/ProjectRunConfigurationManager.kt @@ -0,0 +1,86 @@ +/* + * Copyright 2000-2017 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.execution.impl + +import com.intellij.execution.configurations.UnknownRunConfiguration +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.State +import com.intellij.openapi.components.StateSplitterEx +import com.intellij.openapi.components.Storage +import com.intellij.openapi.options.SchemeManagerFactory +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project +import com.intellij.openapi.startup.StartupActivity +import com.intellij.openapi.util.Pair +import com.intellij.openapi.util.registry.Registry +import gnu.trove.THashSet +import org.jdom.Element + +internal class ProjectRunConfigurationStartupActivity : StartupActivity, DumbAware { + override fun runActivity(project: Project) { + if (project.isDefault || !Registry.`is`("runManager.use.schemeManager", false)) { + return + } + + val manager = RunManagerImpl.getInstanceImpl(project) + val schemeManager = SchemeManagerFactory.getInstance(manager.project).create("runConfigurations", RunConfigurationSchemeManager(manager, true), isUseOldFileNameSanitize = true) + manager.projectSchemeManager = schemeManager + schemeManager.loadSchemes() + manager.requestSort() + } +} + +@State(name = "ProjectRunConfigurationManager", storages = arrayOf(Storage(value = "runConfigurations", stateSplitter = ProjectRunConfigurationManager.RunConfigurationStateSplitter::class))) +internal class ProjectRunConfigurationManager(private val manager: RunManagerImpl) : PersistentStateComponent { + override fun getState(): Element? { + if (Registry.`is`("runManager.use.schemeManager", false)) { + return null + } + + val state = Element("state") + manager.writeConfigurations(state, manager.getSharedConfigurations()) + return state + } + + override fun loadState(state: Element) { + if (Registry.`is`("runManager.use.schemeManager", false)) { + return + } + + val existing = THashSet() + for (child in state.getChildren(RunManagerImpl.CONFIGURATION)) { + existing.add(manager.loadConfiguration(child, true).uniqueID) + } + + manager.removeNotExistingSharedConfigurations(existing) + manager.requestSort() + + if (manager.selectedConfiguration == null) { + for (settings in manager.allSettings) { + if (settings.type !is UnknownRunConfiguration) { + manager.selectedConfiguration = settings + break + } + } + } + } + + internal class RunConfigurationStateSplitter : StateSplitterEx() { + override fun splitState(state: Element): List> { + return StateSplitterEx.splitState(state, RunManagerImpl.NAME_ATTR) + } + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java index b8fdbebf3f9e..22f1f19db84e 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java @@ -182,7 +182,7 @@ class RunConfigurable extends BaseConfigurable { } else if (userObject instanceof RunnerAndConfigurationSettingsImpl) { RunnerAndConfigurationSettings settings = (RunnerAndConfigurationSettings)userObject; - shared = runManager.isConfigurationShared(settings); + shared = settings.isShared(); setIcon(RunManagerEx.getInstanceEx(myProject).getConfigurationIcon(settings)); configuration = settings; } @@ -204,8 +204,7 @@ class RunConfigurable extends BaseConfigurable { } }); final RunManagerEx manager = getRunManager(); - final ConfigurationType[] factories = manager.getConfigurationFactories(); - for (ConfigurationType type : factories) { + for (ConfigurationType type : manager.getConfigurationFactories()) { final List configurations = manager.getConfigurationSettingsList(type); if (!configurations.isEmpty()) { final DefaultMutableTreeNode typeNode = new DefaultMutableTreeNode(type); @@ -232,16 +231,13 @@ class RunConfigurable extends BaseConfigurable { // add defaults final DefaultMutableTreeNode defaults = new DefaultMutableTreeNode(DEFAULTS); - final ConfigurationType[] configurationTypes = RunManagerImpl.getInstanceImpl(myProject).getConfigurationFactories(); - for (final ConfigurationType type : configurationTypes) { - if (!(type instanceof UnknownConfigurationType)) { - ConfigurationFactory[] configurationFactories = type.getConfigurationFactories(); - DefaultMutableTreeNode typeNode = new DefaultMutableTreeNode(type); - defaults.add(typeNode); - if (configurationFactories.length != 1) { - for (ConfigurationFactory factory : configurationFactories) { - typeNode.add(new DefaultMutableTreeNode(factory)); - } + for (final ConfigurationType type : RunManagerImpl.getInstanceImpl(myProject).getConfigurationFactoriesWithoutUnknown()) { + ConfigurationFactory[] configurationFactories = type.getConfigurationFactories(); + DefaultMutableTreeNode typeNode = new DefaultMutableTreeNode(type); + defaults.add(typeNode); + if (configurationFactories.length != 1) { + for (ConfigurationFactory factory : configurationFactories) { + typeNode.add(new DefaultMutableTreeNode(factory)); } } } @@ -668,7 +664,6 @@ class RunConfigurable extends BaseConfigurable { updateActiveConfigurationFromSelected(); final RunManagerImpl manager = getRunManager(); - final ConfigurationType[] types = manager.getConfigurationFactories(); List configurationTypes = new ArrayList<>(); for (int i = 0; i < myRoot.getChildCount(); i++) { final DefaultMutableTreeNode node = (DefaultMutableTreeNode)myRoot.getChildAt(i); @@ -677,7 +672,7 @@ class RunConfigurable extends BaseConfigurable { configurationTypes.add((ConfigurationType)userObject); } } - for (ConfigurationType type : types) { + for (ConfigurationType type : manager.getConfigurationFactories()) { if (!configurationTypes.contains(type)) configurationTypes.add(type); } @@ -709,7 +704,7 @@ class RunConfigurable extends BaseConfigurable { each.first.apply(); } - manager.saveOrder(); + manager.setOrder(null); } finally { getRunManager().fireEndUpdate(); @@ -752,7 +747,7 @@ class RunConfigurable extends BaseConfigurable { else if (userObject instanceof RunnerAndConfigurationSettingsImpl) { settings = (RunnerAndConfigurationSettings)userObject; configurationBean = new RunConfigurationBean(settings, - manager.isConfigurationShared(settings), + settings.isShared(), manager.getBeforeRunTasks(settings.getConfiguration())); } @@ -807,9 +802,7 @@ class RunConfigurable extends BaseConfigurable { toDeleteSettings.remove(each.getSettings()); } - for (RunnerAndConfigurationSettings each : toDeleteSettings) { - manager.removeConfiguration(each); - } + manager.removeConfigurations(toDeleteSettings); } static void collectNodesRecursively(DefaultMutableTreeNode parentNode, List nodes, NodeKind... allowed) { @@ -1126,10 +1119,10 @@ class RunConfigurable extends BaseConfigurable { } private void showAddPopup(final boolean showApplicableTypesOnly) { - ConfigurationType[] allTypes = getRunManager().getConfigurationFactories(false); + List allTypes = getRunManager().getConfigurationFactoriesWithoutUnknown(); final List configurationTypes = getTypesToShow(showApplicableTypesOnly, allTypes); Collections.sort(configurationTypes, (type1, type2) -> type1.getDisplayName().compareToIgnoreCase(type2.getDisplayName())); - final int hiddenCount = allTypes.length - configurationTypes.size(); + final int hiddenCount = allTypes.size() - configurationTypes.size(); if (hiddenCount > 0) { configurationTypes.add(null); } @@ -1140,7 +1133,7 @@ class RunConfigurable extends BaseConfigurable { popup.showUnderneathOf(myToolbarDecorator.getActionsPanel()); } - private List getTypesToShow(boolean showApplicableTypesOnly, ConfigurationType[] allTypes) { + private List getTypesToShow(boolean showApplicableTypesOnly, @NotNull List allTypes) { if (showApplicableTypesOnly) { List applicableTypes = new ArrayList<>(); for (ConfigurationType type : allTypes) { @@ -1148,11 +1141,11 @@ class RunConfigurable extends BaseConfigurable { applicableTypes.add(type); } } - if (applicableTypes.size() < allTypes.length - 3) { + if (applicableTypes.size() < allTypes.size() - 3) { return applicableTypes; } } - return new ArrayList<>(Arrays.asList(allTypes)); + return allTypes; } private boolean isApplicable(ConfigurationType type) { @@ -1672,7 +1665,7 @@ class RunConfigurable extends BaseConfigurable { public RunConfigurationBean(final RunnerAndConfigurationSettings settings, final boolean shared, - final List stepsBeforeLaunch) { + final List> stepsBeforeLaunch) { mySettings = settings; myShared = shared; myStepsBeforeLaunch = Collections.unmodifiableList(stepsBeforeLaunch); diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationBeforeRunProvider.java b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationBeforeRunProvider.java index 440f12c2d6b6..d8112243eb87 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationBeforeRunProvider.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationBeforeRunProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -113,7 +113,7 @@ extends BeforeRunTaskProvider configurations = - RunManagerImpl.getInstanceImpl(runConfiguration.getProject()).getSortedConfigurations(); + RunManagerImpl.getInstanceImpl(runConfiguration.getProject()).getAllSettings(); if (configurations.isEmpty() || (configurations.size() == 1 && configurations.iterator().next().getConfiguration() == runConfiguration)) { return null; @@ -144,7 +144,7 @@ extends BeforeRunTaskProvider configurations = new ArrayList<>(RunManagerImpl.getInstanceImpl(project).getSortedConfigurations()); + List configurations = new ArrayList<>(RunManagerImpl.getInstanceImpl(project).getAllSettings()); String executorId = DefaultRunExecutor.getRunExecutorInstance().getId(); for (Iterator iterator = configurations.iterator(); iterator.hasNext();) { RunnerAndConfigurationSettings settings = iterator.next(); diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationRefactoringElementListenerProvider.java b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationRefactoringElementListenerProvider.java index 94571a9c1927..9a713784c1fe 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationRefactoringElementListenerProvider.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationRefactoringElementListenerProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,8 +25,6 @@ import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.refactoring.listeners.RefactoringElementListenerComposite; import com.intellij.refactoring.listeners.RefactoringElementListenerProvider; -import java.util.List; - /** * @author spleaner */ @@ -36,9 +34,7 @@ public class RunConfigurationRefactoringElementListenerProvider implements Refac @Override public RefactoringElementListener getListener(final PsiElement element) { RefactoringElementListenerComposite composite = null; - final List configurations = RunManager.getInstance(element.getProject()).getAllConfigurationsList(); - - for (RunConfiguration configuration : configurations) { + for (RunConfiguration configuration : RunManager.getInstance(element.getProject()).getAllConfigurationsList()) { if (configuration instanceof RefactoringListenerProvider) { // todo: perhaps better way to handle listeners? RefactoringElementListener listener; try { diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationSchemeManager.kt b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationSchemeManager.kt new file mode 100644 index 000000000000..0780753fc63c --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationSchemeManager.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2017 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.execution.impl + +import com.intellij.configurationStore.LazySchemeProcessor +import com.intellij.configurationStore.SchemeDataHolder +import com.intellij.openapi.util.InvalidDataException +import java.util.function.Function + +internal class RunConfigurationSchemeManager(private val manager: RunManagerImpl, private val isShared: Boolean) : LazySchemeProcessor() { + override fun createScheme(dataHolder: SchemeDataHolder, name: String, attributeProvider: Function, isBundled: Boolean): RunnerAndConfigurationSettingsImpl { + val settings = RunnerAndConfigurationSettingsImpl(manager) + val element = dataHolder.read() + try { + settings.readExternal(element, isShared) + } + catch (e: InvalidDataException) { + RunManagerImpl.LOG.error(e) + } + + manager.addConfiguration(element, settings) + return settings + } + + override fun getName(attributeProvider: Function, fileNameWithoutExtension: String): String { + var name = attributeProvider.apply("name") + if (name == "