Merge remote-tracking branch 'origin/fitermay/PY-20771'
authorLiana.Bakradze <liana.bakradze@jetbrains.com>
Thu, 6 Oct 2016 15:21:30 +0000 (18:21 +0300)
committerLiana.Bakradze <liana.bakradze@jetbrains.com>
Thu, 6 Oct 2016 15:21:30 +0000 (18:21 +0300)
144 files changed:
RegExpSupport/src/org/intellij/lang/regexp/intention/CheckRegExpForm.java
build/scripts/download_jre.gant
java/compiler/impl/src/com/intellij/task/impl/InternalProjectTaskRunner.java
java/compiler/impl/src/com/intellij/task/impl/ModuleBuildTaskImpl.java
java/compiler/impl/src/com/intellij/task/impl/ProjectTaskManagerImpl.java
java/compiler/openapi/src/com/intellij/task/ModuleBuildTask.java
java/compiler/openapi/src/com/intellij/task/ProjectTaskManager.java
java/execution/impl/src/com/intellij/compiler/options/CompileStepBeforeRun.java
java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java
java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMemberFix.java
java/java-impl/src/com/intellij/codeInsight/editorActions/JavaCopyPasteReferenceProcessor.java
java/java-impl/src/com/intellij/codeInspection/streamMigration/MigrateToStreamFix.java
java/java-impl/src/com/intellij/codeInspection/streamMigration/ReplaceWithCollectFix.java
java/java-impl/src/com/intellij/codeInspection/streamMigration/ReplaceWithCountFix.java
java/java-impl/src/com/intellij/codeInspection/streamMigration/ReplaceWithFindFirstFix.java
java/java-impl/src/com/intellij/codeInspection/streamMigration/ReplaceWithForeachCallFix.java
java/java-impl/src/com/intellij/codeInspection/streamMigration/ReplaceWithMatchFix.java
java/java-impl/src/com/intellij/codeInspection/streamMigration/ReplaceWithSumFix.java
java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java
java/java-impl/src/com/intellij/ide/actions/CreateModuleInfoAction.java
java/java-impl/src/com/intellij/javadoc/JavadocHelper.java
java/java-impl/src/com/intellij/psi/impl/file/PsiJavaDirectoryImpl.java
java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java
java/java-impl/src/com/intellij/refactoring/introduceParameter/OldReferenceResolver.java
java/java-impl/src/com/intellij/refactoring/migration/MigrationMapSet.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFlatMapForLoop.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterForLoop.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterForLoopBoxed.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterForLoopShortBound.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterPrimitiveArray.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFindFirstUsedInBound.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFlatMapForLoop.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoop.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopBoxed.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopFloatBound.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopShortBound.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopUpdated.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopWrongBound.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopWrongIncrement.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopWrongInitializer.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforePrimitiveArray.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforePrimitiveArrayWrongType.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeSumAccessOuterFor.java [new file with mode: 0644]
java/java-tests/testData/projectView/contentRootUnderExcluded/B.txt [new file with mode: 0644]
java/java-tests/testData/projectView/contentRootUnderExcluded/exc/excluded.txt [new file with mode: 0644]
java/java-tests/testData/projectView/contentRootUnderExcluded/exc/gen/A.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/codeInsight/editorActions/FixDocCommentTest.groovy
java/java-tests/testSrc/com/intellij/projectView/ProjectTreeStructureTest.java
java/testFramework/src/com/intellij/projectView/BaseProjectViewTestCase.java
jps/jps-builders/src/org/jetbrains/jps/ProjectPaths.java
jps/jps-builders/src/org/jetbrains/jps/builders/artifacts/ArtifactBuildTaskProvider.java
native/WinLauncher/WinLauncher/WinLauncher.cpp
platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java
platform/diff-impl/src/com/intellij/diff/contents/DiffPsiFileType.java
platform/diff-impl/src/com/intellij/diff/tools/holders/TextEditorHolder.java
platform/diff-impl/src/com/intellij/diff/tools/util/side/TwosideTextDiffViewer.java
platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/TaskActivationState.java
platform/lang-impl/src/com/intellij/analysis/actions/ToggleInlineHintsAction.kt [new file with mode: 0644]
platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java
platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ParameterHintsPresentationManager.java
platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/MoverWrapper.java
platform/lang-impl/src/com/intellij/codeInsight/navigation/ImplementationSearcher.java
platform/lang-impl/src/com/intellij/ide/actions/SearchAgainAction.java
platform/lang-impl/src/com/intellij/ide/actions/SearchBackAction.java
platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkAsContentRootAction.kt [new file with mode: 0644]
platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkExcludeRootAction.java
platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java
platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java
platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewModuleNode.java
platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewProjectNode.java
platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesDialog.java
platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java
platform/lang-impl/src/com/intellij/reporting/ReportExcessiveInlineHint.kt [moved from java/java-impl/src/com/intellij/reporting/ReportMissingOrExcessiveInlineHint.kt with 95% similarity]
platform/platform-impl/src/com/intellij/ide/actions/ShowFilePathAction.java
platform/platform-impl/src/com/intellij/ide/customize/CustomizePluginsStepPanel.java
platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/PaintersHelper.java
platform/platform-impl/src/com/intellij/ui/ComboBoxCompositeEditor.java
platform/platform-resources-en/src/messages/ActionsBundle.properties
platform/platform-resources/src/META-INF/PlatformExtensions.xml
platform/platform-resources/src/idea/LangActions.xml
platform/projectModel-api/src/com/intellij/openapi/roots/FileIndex.java
platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java
platform/testFramework/src/com/intellij/projectView/TestProjectTreeStructure.java
platform/util/src/com/intellij/util/ui/UIUtil.java
platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRenderer.java
plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/CyclicClassDependencyInspection.java
plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/DependencyUtils.java
plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/cyclic_class_dependency/expected.xml
plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/cyclic_class_dependency/src/Cyclic.java
plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/try_identical_catches/TryIdenticalCatches.after.java
plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/try_identical_catches/TryIdenticalCatches.java
plugins/devkit/src/dom/KeyboardShortcut.java
plugins/devkit/src/dom/MouseShortcut.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/transformations/TransformationContext.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/transformations/TransformationContextImpl.java
plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java
plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java
plugins/javaFX/testData/highlighting/FxIdUsedInSameNode.java [new file with mode: 0644]
plugins/javaFX/testData/highlighting/fxIdUsedInSameNode.fxml [new file with mode: 0644]
python/ide/src/META-INF/pycharm-core.xml
python/psi-api/src/com/jetbrains/python/PythonStringUtil.java
python/psi-api/src/com/jetbrains/python/psi/PyNumericLiteralExpression.java
python/src/com/jetbrains/python/codeInsight/fstrings/FStringParser.java
python/src/com/jetbrains/python/codeInsight/fstrings/PyFStringsInjector.java
python/src/com/jetbrains/python/editor/BaseQuoteHandler.java
python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java
python/src/com/jetbrains/python/lexer/PyStringLiteralLexer.java
python/src/com/jetbrains/python/lexer/Python.flex
python/src/com/jetbrains/python/psi/PyUtil.java
python/src/com/jetbrains/python/psi/impl/PyNumericLiteralExpressionImpl.java
python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java
python/src/com/jetbrains/python/spellchecker/PythonSpellcheckerStrategy.java
python/src/com/jetbrains/python/validation/FStringsAnnotator.java
python/testData/highlighting/fStringBackslashes.py
python/testData/highlighting/fStringEmptyExpressions.py
python/testData/highlighting/fStringHashSigns.py
python/testData/highlighting/fStringIllegalConversionCharacter.py
python/testData/highlighting/fStringMissingRightBrace.py
python/testData/highlighting/fStringSingleRightBraces.py [new file with mode: 0644]
python/testData/highlighting/fStringTooDeeplyNestedExpressionFragments.py [new file with mode: 0644]
python/testData/inspections/PyUnresolvedReferencesInspection3K/referencesInFStringLiterals.py [new file with mode: 0644]
python/testData/inspections/UnusedLocalDoctestReference/test.py [new file with mode: 0644]
python/testData/inspections/UnusedLocalFStringReferences/test.py [new file with mode: 0644]
python/testData/inspections/spelling/fStringPrefix.py [new file with mode: 0644]
python/testData/inspections/spelling/gluedStringNodesAfterFirstRawWithBackslashes.py [new file with mode: 0644]
python/testData/inspections/spelling/gluedStringNodesAfterFirstWithPrefix.py [new file with mode: 0644]
python/testData/mover/class_afterUp.py
python/testData/mover/lastComment1_afterDown.py
python/testData/optimizeImports/referencesInFStringLiterals.after.py [new file with mode: 0644]
python/testData/optimizeImports/referencesInFStringLiterals.py [new file with mode: 0644]
python/testSrc/com/jetbrains/python/PyEditingTest.java
python/testSrc/com/jetbrains/python/PyFStringTest.java
python/testSrc/com/jetbrains/python/PyNumericLiteralTest.java [new file with mode: 0644]
python/testSrc/com/jetbrains/python/PyOptimizeImportsTest.java
python/testSrc/com/jetbrains/python/PySpellCheckerTest.java
python/testSrc/com/jetbrains/python/PyStringLiteralLexerTest.java
python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
python/testSrc/com/jetbrains/python/PythonInspectionsTest.java
python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java
resources/src/META-INF/IdeaPlugin.xml
resources/src/idea/RichPlatformActions.xml

index 51fc4578920001a6185745c7f697aa519b94d16f..242dae54255b28445ad4a3abbc31e62c562a10ca 100644 (file)
@@ -157,7 +157,7 @@ public class CheckRegExpForm {
       myRootPanel.revalidate();
       Balloon balloon = JBPopupFactory.getInstance().getParentBalloonFor(myRootPanel);
       if (balloon != null) balloon.revalidate();
-    }, ModalityState.current());
+    });
   }
 
   @TestOnly
index 227963c90c4ee4eaeb2c099c00c33907bd92029f..b3b58bb65d601554d2f6e7a47221a2f4adf03325 100644 (file)
@@ -24,6 +24,10 @@ target('default': 'Downloads custom JRE build from Teamcity server') {
     echo "Unsupported platform, JRE download skipped"
     return
   }
+  if (jreArchitecture == "disable") {
+    echo "JRE update disabled"
+    return
+  }
   if (!(jreArchitecture == "64" || jreArchitecture == "32" && platform == "win")) {
     echo "Acceptable architecture (32 or 64 bit) is not defined, JRE download skipped"
     return
index 646594e2d4f8675050bcbcc27a6dae9349271260..5aa4c074f6d2567ed75d8875bc3520a3460a0d56 100644 (file)
@@ -22,6 +22,7 @@ import com.intellij.execution.runners.ExecutionEnvironment;
 import com.intellij.openapi.compiler.CompileScope;
 import com.intellij.openapi.compiler.CompileStatusNotification;
 import com.intellij.openapi.compiler.CompilerManager;
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.vfs.VirtualFile;
@@ -45,6 +46,8 @@ import java.util.stream.Stream;
  * @since 5/11/2016
  */
 public class InternalProjectTaskRunner extends ProjectTaskRunner {
+  private static final Logger LOG = Logger.getInstance(InternalProjectTaskRunner.class);
+
   @Override
   public void run(@NotNull Project project,
                   @NotNull ProjectTaskContext context,
@@ -89,39 +92,60 @@ public class InternalProjectTaskRunner extends ProjectTaskRunner {
 
 
     if (!ContainerUtil.isEmpty(buildTasks)) {
-      List<Module> toMake = new SmartList<>();
-      List<Module> toCompile = new SmartList<>();
+      List<Module> modules = new SmartList<>();
+
+      Boolean isIncrementalBuild = null;
+      Boolean includeDependentModules = null;
+      Boolean includeRuntimeDependencies = null;
 
       for (ProjectTask buildProjectTask : buildTasks) {
         ModuleBuildTask moduleBuildTask = (ModuleBuildTask)buildProjectTask;
-
-        if (moduleBuildTask.isIncrementalBuild()) {
-          toMake.add(moduleBuildTask.getModule());
+        assertModuleBuildSettings(moduleBuildTask, isIncrementalBuild, includeDependentModules, includeRuntimeDependencies);
+        modules.add(moduleBuildTask.getModule());
+        if (!moduleBuildTask.isIncrementalBuild()) {
+          isIncrementalBuild = false;
         }
-        else {
-          toCompile.add(moduleBuildTask.getModule());
+        if (moduleBuildTask.isIncludeDependentModules()) {
+          includeDependentModules = true;
+        }
+        if (moduleBuildTask.isIncludeRuntimeDependencies()) {
+          includeRuntimeDependencies = true;
         }
       }
       CompilerManager compilerManager = CompilerManager.getInstance(project);
-      if (!toMake.isEmpty()) {
-        CompileScope scope = createScope(project, compilerManager, context, toMake);
-        // TODO handle multiple notifications
+      CompileScope scope = createScope(
+        compilerManager, context, modules, includeDependentModules != null, includeRuntimeDependencies != null);
+      if (isIncrementalBuild == null) {
         compilerManager.make(scope, compileNotification);
       }
-      if (!toCompile.isEmpty()) {
-        CompileScope scope = createScope(project, compilerManager, context, toCompile);
-        // TODO handle multiple notifications
+      else {
         compilerManager.compile(scope, compileNotification);
       }
     }
   }
 
+  private static void assertModuleBuildSettings(ModuleBuildTask moduleBuildTask,
+                                                Boolean isIncrementalBuild,
+                                                Boolean includeDependentModules,
+                                                Boolean includeRuntimeDependencies) {
+    if (isIncrementalBuild != null && moduleBuildTask.isIncrementalBuild()) {
+      LOG.warn("Incremental build setting for the module '" + moduleBuildTask.getModule().getName() + "' will be ignored");
+    }
+    if (includeDependentModules != null && !moduleBuildTask.isIncludeDependentModules()) {
+      LOG.warn("'Module '" + moduleBuildTask.getModule().getName() + "' will be built along with dependent modules");
+    }
+    if (includeRuntimeDependencies != null && !moduleBuildTask.isIncludeRuntimeDependencies()) {
+      LOG.warn("'Module '" + moduleBuildTask.getModule().getName() + "' will be built along with runtime dependencies");
+    }
+  }
 
-  private static CompileScope createScope(Project project,
-                                          CompilerManager compilerManager,
+  private static CompileScope createScope(CompilerManager compilerManager,
                                           ProjectTaskContext context,
-                                          Collection<Module> modules) {
-    CompileScope scope = compilerManager.createModuleGroupCompileScope(project, modules.toArray(new Module[modules.size()]), true);
+                                          Collection<Module> modules,
+                                          boolean includeDependentModules,
+                                          boolean includeRuntimeDependencies) {
+    CompileScope scope = compilerManager.createModulesCompileScope(
+      modules.toArray(new Module[modules.size()]), includeDependentModules, includeRuntimeDependencies);
     RunConfiguration configuration = context.getRunConfiguration();
     if (configuration != null) {
       scope.putUserData(CompilerManager.RUN_CONFIGURATION_KEY, configuration);
index 6ae30a5512ef2b1e2c0d2a16a9c9fc91ee6ebd62..49132691e61cd88f58807578a2c1b0353f19626c 100644 (file)
@@ -26,10 +26,21 @@ import org.jetbrains.annotations.NotNull;
 public class ModuleBuildTaskImpl extends AbstractBuildTask implements ModuleBuildTask {
   @NotNull
   private final Module myModule;
+  private final boolean myIncludeDependentModules;
+  private final boolean myIncludeRuntimeDependencies;
 
   public ModuleBuildTaskImpl(@NotNull Module module, boolean isIncrementalBuild) {
+    this(module, isIncrementalBuild, false, false);
+  }
+
+  public ModuleBuildTaskImpl(@NotNull Module module,
+                             boolean isIncrementalBuild,
+                             boolean includeDependentModules,
+                             boolean includeRuntimeDependencies) {
     super(isIncrementalBuild);
     myModule = module;
+    myIncludeDependentModules = includeDependentModules;
+    myIncludeRuntimeDependencies = includeRuntimeDependencies;
   }
 
   @NotNull
@@ -38,6 +49,16 @@ public class ModuleBuildTaskImpl extends AbstractBuildTask implements ModuleBuil
     return myModule;
   }
 
+  @Override
+  public boolean isIncludeDependentModules() {
+    return myIncludeDependentModules;
+  }
+
+  @Override
+  public boolean isIncludeRuntimeDependencies() {
+    return myIncludeRuntimeDependencies;
+  }
+
   @NotNull
   @Override
   public String getPresentableName() {
index 21eff5a8ff5935fdb03bbc81488688220f335a05..b370a4d228510bfc2b5819d42841b6069640f616 100644 (file)
@@ -25,6 +25,7 @@ import com.intellij.packaging.artifacts.Artifact;
 import com.intellij.task.*;
 import com.intellij.util.Consumer;
 import com.intellij.util.SmartList;
+import com.intellij.util.containers.ContainerUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -50,12 +51,12 @@ public class ProjectTaskManagerImpl extends ProjectTaskManager {
 
   @Override
   public void build(@NotNull Module[] modules, @Nullable ProjectTaskNotification callback) {
-    run(createModulesBuildTask(true, modules), callback);
+    run(createModulesBuildTask(modules, true, true, false), callback);
   }
 
   @Override
   public void rebuild(@NotNull Module[] modules, @Nullable ProjectTaskNotification callback) {
-    run(createModulesBuildTask(false, modules), callback);
+    run(createModulesBuildTask(modules, false, false, false), callback);
   }
 
   @Override
@@ -91,14 +92,26 @@ public class ProjectTaskManagerImpl extends ProjectTaskManager {
 
   @Override
   public ProjectTask createAllModulesBuildTask(boolean isIncrementalBuild, Project project) {
-    return createModulesBuildTask(isIncrementalBuild, ModuleManager.getInstance(project).getModules());
+    return createModulesBuildTask(ModuleManager.getInstance(project).getModules(), isIncrementalBuild, false, false);
   }
 
   @Override
-  public ProjectTask createModulesBuildTask(boolean isIncrementalBuild, Module... modules) {
+  public ProjectTask createModulesBuildTask(Module module,
+                                            boolean isIncrementalBuild,
+                                            boolean includeDependentModules,
+                                            boolean includeRuntimeDependencies) {
+    return createModulesBuildTask(ContainerUtil.ar(module), isIncrementalBuild, includeDependentModules, includeRuntimeDependencies);
+  }
+
+  @Override
+  public ProjectTask createModulesBuildTask(Module[] modules,
+                                            boolean isIncrementalBuild,
+                                            boolean includeDependentModules,
+                                            boolean includeRuntimeDependencies) {
     return modules.length == 1
-           ? new ModuleBuildTaskImpl(modules[0], isIncrementalBuild)
-           : new ProjectTaskList(map(list(modules), module -> new ModuleBuildTaskImpl(module, isIncrementalBuild)));
+           ? new ModuleBuildTaskImpl(modules[0], isIncrementalBuild, includeDependentModules, includeRuntimeDependencies)
+           : new ProjectTaskList(map(list(modules), module ->
+             new ModuleBuildTaskImpl(module, isIncrementalBuild, includeDependentModules, includeRuntimeDependencies)));
   }
 
   @Override
index ad08c7d474f1c7e01a458206a320b4508e74c594..c0e74d10454d266909e070048ad1524dd66cebe4 100644 (file)
@@ -25,4 +25,8 @@ import org.jetbrains.annotations.NotNull;
 public interface ModuleBuildTask extends BuildTask {
   @NotNull
   Module getModule();
+
+  boolean isIncludeDependentModules();
+
+  boolean isIncludeRuntimeDependencies();
 }
index fe3d8474f1289ad2143d0fb3ee59921ca3ba2cc8..46570c3911de569b1c9f13a8fd925b0f45b1ee84 100644 (file)
@@ -91,7 +91,15 @@ public abstract class ProjectTaskManager {
 
   public abstract ProjectTask createAllModulesBuildTask(boolean isIncrementalBuild, Project project);
 
-  public abstract ProjectTask createModulesBuildTask(boolean isIncrementalBuild, Module... modules);
+  public abstract ProjectTask createModulesBuildTask(Module module,
+                                                     boolean isIncrementalBuild,
+                                                     boolean includeDependentModules,
+                                                     boolean includeRuntimeDependencies);
+
+  public abstract ProjectTask createModulesBuildTask(Module[] modules,
+                                                     boolean isIncrementalBuild,
+                                                     boolean includeDependentModules,
+                                                     boolean includeRuntimeDependencies);
 
   public abstract ProjectTask createArtifactsBuildTask(boolean isIncrementalBuild, Artifact... artifacts);
 
index 6aaf886ef996adf9e5334ffd5f1a5066e9c505cc..96d42d2aaf750cd4355981e6a49179145434e6ee 100644 (file)
@@ -164,7 +164,7 @@ public class CompileStepBeforeRun extends BeforeRunTaskProvider<CompileStepBefor
                           runConfiguration.getClass().getName());
               }
             }
-            projectTask = projectTaskManager.createModulesBuildTask(true, modules);
+            projectTask = projectTaskManager.createModulesBuildTask(modules, true, true, true);
           }
           else {
             projectTask = projectTaskManager.createAllModulesBuildTask(true, myProject);
index 1a648d2a1aed2753bcbd32c829b09803c66b502c..d9d81f92a0c5c438f898316c5cb475dec7411c32 100644 (file)
@@ -732,7 +732,18 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
       }
     }
     if (!myHolder.hasErrorResults()) {
-      final PsiElement resolved = results.length == 1 ? results[0].getElement() : null;
+      PsiElement resolved = results.length >= 1 ? results[0].getElement() : null;
+      if (results.length > 1) {
+        for (int i = 1; i < results.length; i++) {
+          final PsiElement element = results[i].getElement();
+          if (resolved instanceof PsiMethod && !(element instanceof PsiMethod) ||
+              resolved instanceof PsiVariable && !(element instanceof PsiVariable) ||
+              resolved instanceof PsiClass && !(element instanceof PsiClass)) {
+            resolved = null;
+            break;
+          }
+        }
+      }
       final TextAttributesScheme colorsScheme = myHolder.getColorsScheme();
       if (resolved instanceof PsiClass) {
         myHolder.add(HighlightNamesUtil.highlightClassName((PsiClass)resolved, ref, colorsScheme));
index 539075b5fd12fc271192e71659584fc44c357ebe..ded7d252ae48c2486cbd90b43994ac6c0dc6068f 100644 (file)
@@ -401,12 +401,10 @@ public class DuplicatesFinder {
       final PsiType type1 = ((PsiNewExpression)pattern).getType();
       final PsiType type2 = ((PsiNewExpression)candidate).getType();
       if (type1 == null || type2 == null) return false;
-      final PsiJavaCodeReferenceElement classReference1 = ((PsiNewExpression)pattern).getClassReference();
-      final PsiJavaCodeReferenceElement classReference2 = ((PsiNewExpression)candidate).getClassReference();
-      if (classReference1 != null && classReference2 != null) {
-        final PsiElement resolved1 = classReference1.resolve();
-        final PsiElement resolved2 = classReference2.resolve();
-        if (!pattern.getManager().areElementsEquivalent(resolved1, resolved2)) return false;
+      final PsiMethod constructor1 = ((PsiNewExpression)pattern).resolveConstructor();
+      final PsiMethod constructor2 = ((PsiNewExpression)candidate).resolveConstructor();
+      if (constructor1 != null && constructor2 != null) {
+        if (!pattern.getManager().areElementsEquivalent(constructor1, constructor2)) return false;
       }
       else {
         if (!canTypesBeEquivalent(type1, type2)) return false;
index 48d9d24ad0e55e5c1982f7901ac9f831baf4e687..0134261cbf036d7ab31f6b836a0e5ef5f83de266 100644 (file)
@@ -24,17 +24,13 @@ import com.intellij.codeInsight.hint.HintManager;
 import com.intellij.codeInsight.hint.QuestionAction;
 import com.intellij.codeInsight.intention.IntentionAction;
 import com.intellij.codeInspection.HintAction;
-import com.intellij.lang.java.JavaLanguage;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.application.impl.LaterInvocator;
 import com.intellij.openapi.command.CommandProcessor;
 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.psi.PsiFile;
-import com.intellij.psi.PsiJavaFile;
-import com.intellij.psi.PsiMember;
+import com.intellij.psi.*;
 import com.intellij.psi.util.FileTypeUtils;
 import com.intellij.psi.util.PsiUtil;
 import org.jetbrains.annotations.NotNull;
@@ -79,7 +75,11 @@ public abstract class StaticImportMemberFix<T extends PsiMember> implements Inte
            && !(candidates == null ? candidates = getMembersToImport(false) : candidates).isEmpty()
       ;
   }
-  
+
+  public final List<T> getMembersToImport() {
+    return getMembersToImport(false);
+  }
+
   @NotNull protected abstract List<T> getMembersToImport(boolean applicableOnly);
 
   public static boolean isExcluded(PsiMember method) {
index 70460bfca8ea6ed284e190542311d9b6ea02b7a4..d7dea455820ab04b687d4e0f563ac28bc898f813 100644 (file)
@@ -17,11 +17,14 @@ package com.intellij.codeInsight.editorActions;
 
 import com.intellij.codeInsight.CodeInsightSettings;
 import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFix;
+import com.intellij.codeInsight.daemon.impl.quickfix.StaticImportConstantFix;
+import com.intellij.codeInsight.daemon.impl.quickfix.StaticImportMethodFix;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.RangeMarker;
 import com.intellij.openapi.util.TextRange;
 import com.intellij.psi.*;
 import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.ArrayList;
 
@@ -103,10 +106,10 @@ public class JavaCopyPasteReferenceProcessor extends CopyPasteReferenceProcessor
       }
     }
 
-    if (CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY) {
+    if (CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY ||
+        CodeInsightSettings.getInstance().ADD_MEMBER_IMPORTS_ON_THE_FLY) {
       for (int i = 0; i < refs.length; i++) {
-        PsiJavaCodeReferenceElement ref = refs[i];
-        if (ref != null && new ImportClassFix(ref).getClassesToImport().size() <= 1) {
+        if (isUnambiguous(refs[i])) {
           refs[i] = null;
         }
       }
@@ -115,6 +118,23 @@ public class JavaCopyPasteReferenceProcessor extends CopyPasteReferenceProcessor
     return refs;
   }
 
+  private static boolean isUnambiguous(@Nullable PsiJavaCodeReferenceElement ref) {
+    if (ref == null) return false;
+
+    PsiElement parent = ref.getParent();
+    if (parent instanceof PsiMethodCallExpression) {
+      return CodeInsightSettings.getInstance().ADD_MEMBER_IMPORTS_ON_THE_FLY &&
+             new StaticImportMethodFix((PsiMethodCallExpression)parent).getMembersToImport().size() <= 1;
+    }
+
+    int constCount = new StaticImportConstantFix(ref).getMembersToImport().size();
+    int classCount = new ImportClassFix(ref).getClassesToImport().size();
+    if (constCount + classCount > 1) return false;
+    if (constCount + classCount == 0) return true;
+    return constCount == 1 ? CodeInsightSettings.getInstance().ADD_MEMBER_IMPORTS_ON_THE_FLY
+                           : CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY;
+  }
+
   @Override
   protected void restoreReferences(ReferenceData[] referenceData,
                                         PsiJavaCodeReferenceElement[] refs) {
index aeb404a75230a029d4d1563b30ff748132d9ca51..5a1a4c2d058356aff77acb14d608863774d34aff 100644 (file)
@@ -19,9 +19,7 @@ import com.intellij.codeInsight.FileModificationService;
 import com.intellij.codeInspection.LambdaCanBeMethodReferenceInspection;
 import com.intellij.codeInspection.LocalQuickFix;
 import com.intellij.codeInspection.ProblemDescriptor;
-import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus;
-import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.Operation;
-import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.TerminalBlock;
+import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.*;
 import com.intellij.openapi.project.Project;
 import com.intellij.psi.*;
 import com.intellij.psi.codeStyle.CodeStyleManager;
@@ -30,7 +28,6 @@ import com.intellij.psi.util.PsiTreeUtil;
 import com.siyeh.ig.psiutils.ExpressionUtils;
 import one.util.streamex.StreamEx;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
 import java.util.ListIterator;
@@ -49,65 +46,61 @@ abstract class MigrateToStreamFix implements LocalQuickFix {
   @Override
   public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
     PsiElement element = descriptor.getPsiElement();
-    if (element instanceof PsiForeachStatement) {
-      PsiForeachStatement foreachStatement = (PsiForeachStatement)element;
-      PsiStatement body = foreachStatement.getBody();
-      final PsiExpression iteratedValue = foreachStatement.getIteratedValue();
-      if (body != null && iteratedValue != null) {
-        final PsiParameter parameter = foreachStatement.getIterationParameter();
-        TerminalBlock tb = TerminalBlock.from(parameter, body);
-        if (!FileModificationService.getInstance().preparePsiElementForWrite(foreachStatement)) return;
-        PsiElement result = migrate(project, descriptor, foreachStatement, iteratedValue, body, tb);
-        if(result != null) {
-          simplifyAndFormat(project, result);
-        }
+    if (element instanceof PsiLoopStatement) {
+      PsiLoopStatement loopStatement = (PsiLoopStatement)element;
+      StreamSource source = StreamSource.tryCreate(loopStatement);
+      PsiStatement body = loopStatement.getBody();
+      if(body == null || source == null) return;
+      TerminalBlock tb = TerminalBlock.from(source, body);
+      if (!FileModificationService.getInstance().preparePsiElementForWrite(loopStatement)) return;
+      PsiElement result = migrate(project, loopStatement, body, tb);
+      if(result != null) {
+        simplifyAndFormat(project, result);
       }
     }
   }
 
   abstract PsiElement migrate(@NotNull Project project,
-                        @NotNull ProblemDescriptor descriptor,
-                        @NotNull PsiForeachStatement foreachStatement,
-                        @NotNull PsiExpression iteratedValue,
-                        @NotNull PsiStatement body,
-                        @NotNull TerminalBlock tb);
+                              @NotNull PsiLoopStatement loopStatement,
+                              @NotNull PsiStatement body,
+                              @NotNull TerminalBlock tb);
 
   static PsiElement replaceWithNumericAddition(@NotNull Project project,
-                                               PsiForeachStatement foreachStatement,
+                                               PsiLoopStatement loopStatement,
                                                PsiVariable var,
                                                StringBuilder builder,
                                                PsiType expressionType) {
     PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
-    restoreComments(foreachStatement, foreachStatement.getBody());
-    InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, foreachStatement);
+    restoreComments(loopStatement, loopStatement.getBody());
+    InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, loopStatement);
     if (status != InitializerUsageStatus.UNKNOWN) {
       PsiExpression initializer = var.getInitializer();
       if (ExpressionUtils.isZero(initializer)) {
         PsiType type = var.getType();
         String replacement = (type.equals(expressionType) ? "" : "(" + type.getCanonicalText() + ") ") + builder;
-        return replaceInitializer(foreachStatement, var, initializer, replacement, status);
+        return replaceInitializer(loopStatement, var, initializer, replacement, status);
       }
     }
-    return foreachStatement.replace(elementFactory.createStatementFromText(var.getName() + "+=" + builder + ";", foreachStatement));
+    return loopStatement.replace(elementFactory.createStatementFromText(var.getName() + "+=" + builder + ";", loopStatement));
   }
 
-  static PsiElement replaceInitializer(PsiForeachStatement foreachStatement,
+  static PsiElement replaceInitializer(PsiLoopStatement loopStatement,
                                  PsiVariable var,
                                  PsiExpression initializer,
                                  String replacement,
                                  InitializerUsageStatus status) {
-    Project project = foreachStatement.getProject();
+    Project project = loopStatement.getProject();
     PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
     if(status == InitializerUsageStatus.DECLARED_JUST_BEFORE) {
-      initializer.replace(elementFactory.createExpressionFromText(replacement, foreachStatement));
-      removeLoop(foreachStatement);
+      initializer.replace(elementFactory.createExpressionFromText(replacement, loopStatement));
+      removeLoop(loopStatement);
       return var;
     } else {
       if(status == InitializerUsageStatus.AT_WANTED_PLACE_ONLY) {
         initializer.delete();
       }
       return
-        foreachStatement.replace(elementFactory.createStatementFromText(var.getName() + " = " + replacement + ";", foreachStatement));
+        loopStatement.replace(elementFactory.createStatementFromText(var.getName() + " = " + replacement + ";", loopStatement));
     }
   }
 
@@ -117,34 +110,26 @@ abstract class MigrateToStreamFix implements LocalQuickFix {
     CodeStyleManager.getInstance(project).reformat(JavaCodeStyleManager.getInstance(project).shortenClassReferences(result));
   }
 
-  static void restoreComments(PsiForeachStatement foreachStatement, PsiStatement body) {
-    final PsiElement parent = foreachStatement.getParent();
+  static void restoreComments(PsiLoopStatement loopStatement, PsiStatement body) {
+    final PsiElement parent = loopStatement.getParent();
     for (PsiElement comment : PsiTreeUtil.findChildrenOfType(body, PsiComment.class)) {
-      parent.addBefore(comment, foreachStatement);
+      parent.addBefore(comment, loopStatement);
     }
   }
 
   @NotNull
-  static StringBuilder generateStream(PsiExpression iteratedValue, @Nullable Operation lastOperation) {
-    return generateStream(iteratedValue, lastOperation, false);
+  static StringBuilder generateStream(@NotNull Operation lastOperation) {
+    return generateStream(lastOperation, false);
   }
 
   @NotNull
-  static StringBuilder generateStream(PsiExpression iteratedValue, @Nullable Operation lastOperation, boolean noStreamForEmpty) {
+  static StringBuilder generateStream(@NotNull Operation lastOperation, boolean noStreamForEmpty) {
     StringBuilder buffer = new StringBuilder();
-    final PsiType iteratedValueType = iteratedValue.getType();
-    if (iteratedValueType instanceof PsiArrayType) {
-      buffer.append("java.util.Arrays.stream(").append(iteratedValue.getText()).append(")");
+    if(noStreamForEmpty && lastOperation instanceof CollectionStream) {
+      return buffer.append(lastOperation.getExpression().getText());
     }
-    else {
-      buffer.append(getIteratedValueText(iteratedValue));
-      if (!noStreamForEmpty || lastOperation != null) {
-        buffer.append(".stream()");
-      }
-    }
-    PsiElementFactory factory = JavaPsiFacade.getElementFactory(iteratedValue.getProject());
     List<String> replacements =
-      StreamEx.iterate(lastOperation, Objects::nonNull, Operation::getPreviousOp).map(op -> op.createReplacement(factory)).toList();
+      StreamEx.iterate(lastOperation, Objects::nonNull, Operation::getPreviousOp).map(Operation::createReplacement).toList();
     for(ListIterator<String> it = replacements.listIterator(replacements.size()); it.hasPrevious(); ) {
       buffer.append(it.previous());
     }
@@ -158,7 +143,7 @@ abstract class MigrateToStreamFix implements LocalQuickFix {
            iteratedValue instanceof PsiParenthesizedExpression ? iteratedValue.getText() : "(" + iteratedValue.getText() + ")";
   }
 
-  static void removeLoop(@NotNull PsiForeachStatement statement) {
+  static void removeLoop(@NotNull PsiLoopStatement statement) {
     PsiElement parent = statement.getParent();
     if (parent instanceof PsiLabeledStatement) {
       parent.delete();
index 4dd8e7c06070ce5fc49e368d2227602ff45aa2b2..74c85641b70145cebb8c81d4d2365ba0999d955c 100644 (file)
@@ -15,8 +15,8 @@
  */
 package com.intellij.codeInspection.streamMigration;
 
-import com.intellij.codeInspection.ProblemDescriptor;
 import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus;
+import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.MapOp;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.text.StringUtil;
@@ -58,42 +58,41 @@ class ReplaceWithCollectFix extends MigrateToStreamFix {
 
   @Override
   PsiElement migrate(@NotNull Project project,
-               @NotNull ProblemDescriptor descriptor,
-               @NotNull PsiForeachStatement foreachStatement,
-               @NotNull PsiExpression iteratedValue,
-               @NotNull PsiStatement body,
-               @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
+                     @NotNull PsiLoopStatement loopStatement,
+                     @NotNull PsiStatement body,
+                     @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
     final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
-    final PsiType iteratedValueType = iteratedValue.getType();
     final PsiMethodCallExpression methodCallExpression = tb.getSingleMethodCall();
 
     if (methodCallExpression == null) return null;
 
-    restoreComments(foreachStatement, body);
-    if (!tb.hasOperations() && StreamApiMigrationInspection.isAddAllCall(tb)) {
+    restoreComments(loopStatement, body);
+    if (!tb.hasOperations() && StreamApiMigrationInspection.isAddAllCall(tb) && loopStatement instanceof PsiForeachStatement) {
+      PsiExpression iteratedValue = ((PsiForeachStatement)loopStatement).getIteratedValue();
+      if (iteratedValue == null) return null;
+      final PsiType iteratedValueType = iteratedValue.getType();
       final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression();
       final String qualifierText = qualifierExpression != null ? qualifierExpression.getText() : "";
       final String collectionText =
         iteratedValueType instanceof PsiArrayType ? "java.util.Arrays.asList(" + iteratedValue.getText() + ")" :
         getIteratedValueText(iteratedValue);
       final String callText = StringUtil.getQualifiedName(qualifierText, "addAll(" + collectionText + ");");
-      return foreachStatement.replace(elementFactory.createStatementFromText(callText, foreachStatement));
+      return loopStatement.replace(elementFactory.createStatementFromText(callText, loopStatement));
     }
     PsiExpression itemToAdd = methodCallExpression.getArgumentList().getExpressions()[0];
     PsiType addedType = getAddedElementType(methodCallExpression);
     if (addedType == null) addedType = itemToAdd.getType();
-    final StringBuilder builder =
-      generateStream(iteratedValue, new StreamApiMigrationInspection.MapOp(tb.getLastOperation(), itemToAdd, tb.getVariable(), addedType));
+    StringBuilder builder = generateStream(new MapOp(tb.getLastOperation(), itemToAdd, tb.getVariable(), addedType));
 
     final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression();
     final PsiLocalVariable variable = StreamApiMigrationInspection.extractCollectionVariable(qualifierExpression);
     if (variable != null) {
-      InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(variable, foreachStatement);
+      InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(variable, loopStatement);
       if(status != InitializerUsageStatus.UNKNOWN) {
         PsiExpression initializer = variable.getInitializer();
         LOG.assertTrue(initializer != null);
         PsiMethodCallExpression toArrayExpression =
-          StreamApiMigrationInspection.extractToArrayExpression(foreachStatement, methodCallExpression);
+          StreamApiMigrationInspection.extractToArrayExpression(loopStatement, methodCallExpression);
         if(toArrayExpression != null) {
           PsiType type = initializer.getType();
           if(type instanceof PsiClassType) {
@@ -113,7 +112,7 @@ class ReplaceWithCollectFix extends MigrateToStreamFix {
               }
               PsiElement result =
                 toArrayExpression.replace(elementFactory.createExpressionFromText(builder.toString(), toArrayExpression));
-              removeLoop(foreachStatement);
+              removeLoop(loopStatement);
               if(status != InitializerUsageStatus.AT_WANTED_PLACE) {
                 variable.delete();
               }
@@ -121,7 +120,7 @@ class ReplaceWithCollectFix extends MigrateToStreamFix {
             }
           }
         }
-        PsiElement nextStatement = PsiTreeUtil.skipSiblingsForward(foreachStatement, PsiComment.class, PsiWhiteSpace.class);
+        PsiElement nextStatement = PsiTreeUtil.skipSiblingsForward(loopStatement, PsiComment.class, PsiWhiteSpace.class);
         String comparatorText = StreamApiMigrationInspection.tryExtractSortComparatorText(nextStatement, variable);
         if(comparatorText != null) {
           builder.append(".sorted(").append(comparatorText).append(")");
@@ -130,7 +129,7 @@ class ReplaceWithCollectFix extends MigrateToStreamFix {
         String callText = builder.append(".collect(java.util.stream.Collectors.")
           .append(createInitializerReplacementText(qualifierExpression.getType(), initializer))
           .append(")").toString();
-        return replaceInitializer(foreachStatement, variable, initializer, callText, status);
+        return replaceInitializer(loopStatement, variable, initializer, callText, status);
       }
     }
     final String qualifierText = qualifierExpression != null ? qualifierExpression.getText() + "." : "";
@@ -147,7 +146,7 @@ class ReplaceWithCollectFix extends MigrateToStreamFix {
       elementFactory.createExpressionFromText(qualifierText + "add(" + varName + ")", qualifierExpression);
     final String callText =
       builder.append(".forEach(").append(varName).append("->").append(forEachBody.getText()).append(");").toString();
-    return foreachStatement.replace(elementFactory.createStatementFromText(callText, foreachStatement));
+    return loopStatement.replace(elementFactory.createStatementFromText(callText, loopStatement));
   }
 
   private static String createInitializerReplacementText(PsiType varType, PsiExpression initializer) {
index 836aa8b629b872136d8a450679b87adcc02b7b43..137630e080dead5def657b7c966d273b9c869dfb 100644 (file)
@@ -15,7 +15,6 @@
  */
 package com.intellij.codeInspection.streamMigration;
 
-import com.intellij.codeInspection.ProblemDescriptor;
 import com.intellij.openapi.project.Project;
 import com.intellij.psi.*;
 import org.jetbrains.annotations.NotNull;
@@ -33,18 +32,15 @@ class ReplaceWithCountFix extends MigrateToStreamFix {
 
   @Override
   PsiElement migrate(@NotNull Project project,
-               @NotNull ProblemDescriptor descriptor,
-               @NotNull PsiForeachStatement foreachStatement,
-               @NotNull PsiExpression iteratedValue,
-               @NotNull PsiStatement body,
-               @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
+                     @NotNull PsiLoopStatement loopStatement,
+                     @NotNull PsiStatement body,
+                     @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
     PsiExpression operand = StreamApiMigrationInspection.extractIncrementedLValue(tb.getSingleExpression(PsiExpression.class));
     if (!(operand instanceof PsiReferenceExpression)) return null;
     PsiElement element = ((PsiReferenceExpression)operand).resolve();
     if (!(element instanceof PsiLocalVariable)) return null;
     PsiLocalVariable var = (PsiLocalVariable)element;
-    final StringBuilder builder = generateStream(iteratedValue, tb.getLastOperation());
-    builder.append(".count()");
-    return replaceWithNumericAddition(project, foreachStatement, var, builder, PsiType.LONG);
+    StringBuilder builder = generateStream(tb.getLastOperation()).append(".count()");
+    return replaceWithNumericAddition(project, loopStatement, var, builder, PsiType.LONG);
   }
 }
index 68fcfca7a55693b26415dc2f946a0426d172de36..ff9b77733dfeaeac4d8b035bbe40513978745991 100644 (file)
@@ -16,7 +16,6 @@
 package com.intellij.codeInspection.streamMigration;
 
 import com.intellij.codeInsight.PsiEquivalenceUtil;
-import com.intellij.codeInspection.ProblemDescriptor;
 import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus;
 import com.intellij.openapi.project.Project;
 import com.intellij.psi.*;
@@ -36,28 +35,27 @@ class ReplaceWithFindFirstFix extends MigrateToStreamFix {
 
   @Override
   PsiElement migrate(@NotNull Project project,
-               @NotNull ProblemDescriptor descriptor,
-               @NotNull PsiForeachStatement foreachStatement,
-               @NotNull PsiExpression iteratedValue,
-               @NotNull PsiStatement body,
-               @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
+                     @NotNull PsiLoopStatement loopStatement,
+                     @NotNull PsiStatement body,
+                     @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
     PsiStatement statement = tb.getSingleStatement();
     PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
-    String stream = generateStream(iteratedValue, tb.getLastOperation()).append(".findFirst()").toString();
+    StringBuilder builder = generateStream(tb.getLastOperation());
+    String stream = builder.append(".findFirst()").toString();
     if (statement instanceof PsiReturnStatement) {
       PsiReturnStatement returnStatement = (PsiReturnStatement)statement;
       PsiExpression value = returnStatement.getReturnValue();
       if (value == null) return null;
-      PsiReturnStatement nextReturnStatement = StreamApiMigrationInspection.getNextReturnStatement(foreachStatement);
+      PsiReturnStatement nextReturnStatement = StreamApiMigrationInspection.getNextReturnStatement(loopStatement);
       if (nextReturnStatement == null) return null;
       PsiExpression orElseExpression = nextReturnStatement.getReturnValue();
       if (!ExpressionUtils.isSimpleExpression(orElseExpression)) return null;
       stream = generateOptionalUnwrap(stream, tb, value, orElseExpression, null);
-      restoreComments(foreachStatement, body);
-      if (nextReturnStatement.getParent() == foreachStatement.getParent()) {
+      restoreComments(loopStatement, body);
+      if (nextReturnStatement.getParent() == loopStatement.getParent()) {
         nextReturnStatement.delete();
       }
-      return foreachStatement.replace(elementFactory.createStatementFromText("return " + stream + ";", foreachStatement));
+      return loopStatement.replace(elementFactory.createStatementFromText("return " + stream + ";", loopStatement));
     }
     else {
       PsiStatement[] statements = tb.getStatements();
@@ -66,9 +64,9 @@ class ReplaceWithFindFirstFix extends MigrateToStreamFix {
       if (assignment == null) {
         if(!(statements[0] instanceof PsiExpressionStatement)) return null;
         PsiExpression expression = ((PsiExpressionStatement)statements[0]).getExpression();
-        restoreComments(foreachStatement, body);
-        return foreachStatement.replace(elementFactory.createStatementFromText(
-          stream + ".ifPresent(" + LambdaUtil.createLambda(tb.getVariable(), expression) + ");", foreachStatement));
+        restoreComments(loopStatement, body);
+        return loopStatement.replace(elementFactory.createStatementFromText(
+          stream + ".ifPresent(" + LambdaUtil.createLambda(tb.getVariable(), expression) + ");", loopStatement));
       }
       PsiExpression lValue = assignment.getLExpression();
       if (!(lValue instanceof PsiReferenceExpression)) return null;
@@ -77,17 +75,17 @@ class ReplaceWithFindFirstFix extends MigrateToStreamFix {
       PsiVariable var = (PsiVariable)element;
       PsiExpression value = assignment.getRExpression();
       if (value == null) return null;
-      restoreComments(foreachStatement, body);
-      InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, foreachStatement);
+      restoreComments(loopStatement, body);
+      InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, loopStatement);
       if (status != InitializerUsageStatus.UNKNOWN) {
         PsiExpression initializer = var.getInitializer();
         if (initializer != null) {
           String replacementText = generateOptionalUnwrap(stream, tb, value, initializer, var.getType());
-          return replaceInitializer(foreachStatement, var, initializer, replacementText, status);
+          return replaceInitializer(loopStatement, var, initializer, replacementText, status);
         }
       }
-      return foreachStatement.replace(elementFactory.createStatementFromText(
-        var.getName() + " = " + generateOptionalUnwrap(stream, tb, value, lValue, var.getType()) + ";", foreachStatement));
+      return loopStatement.replace(elementFactory.createStatementFromText(
+        var.getName() + " = " + generateOptionalUnwrap(stream, tb, value, lValue, var.getType()) + ";", loopStatement));
     }
   }
 
index 6abacc64aa3ee9b1da3c2cc1e6b252a3b14642ea..becd6fd93e5783296462c1d94b9220ad2a49784f 100644 (file)
@@ -15,7 +15,6 @@
  */
 package com.intellij.codeInspection.streamMigration;
 
-import com.intellij.codeInspection.ProblemDescriptor;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.project.Project;
 import com.intellij.psi.*;
@@ -41,24 +40,22 @@ class ReplaceWithForeachCallFix extends MigrateToStreamFix {
 
   @Override
   PsiElement migrate(@NotNull Project project,
-               @NotNull ProblemDescriptor descriptor,
-               @NotNull PsiForeachStatement foreachStatement,
-               @NotNull PsiExpression iteratedValue,
-               @NotNull PsiStatement body,
-               @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
-    restoreComments(foreachStatement, body);
+                     @NotNull PsiLoopStatement loopStatement,
+                     @NotNull PsiStatement body,
+                     @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
+    restoreComments(loopStatement, body);
 
     final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
 
-    StringBuilder buffer = generateStream(iteratedValue, tb.getLastOperation(), true);
+    StringBuilder buffer = generateStream(tb.getLastOperation(), true);
     PsiElement block = tb.convertToElement(elementFactory);
 
     buffer.append(".").append(myForEachMethodName).append("(");
 
     final String functionalExpressionText = tb.getVariable().getName() + " -> " + wrapInBlock(block);
     PsiExpressionStatement callStatement = (PsiExpressionStatement)elementFactory
-      .createStatementFromText(buffer.toString() + functionalExpressionText + ");", foreachStatement);
-    callStatement = (PsiExpressionStatement)foreachStatement.replace(callStatement);
+      .createStatementFromText(buffer.toString() + functionalExpressionText + ");", loopStatement);
+    callStatement = (PsiExpressionStatement)loopStatement.replace(callStatement);
 
     final PsiExpressionList argumentList = ((PsiCallExpression)callStatement.getExpression()).getArgumentList();
     LOG.assertTrue(argumentList != null, callStatement.getText());
index d2a482e781905ffff3a72ae564949a1507e31e3a..1053a306f89c0fcba6eccad511f158218ddb1df5 100644 (file)
@@ -15,7 +15,6 @@
  */
 package com.intellij.codeInspection.streamMigration;
 
-import com.intellij.codeInspection.ProblemDescriptor;
 import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.project.Project;
@@ -46,43 +45,40 @@ class ReplaceWithMatchFix extends MigrateToStreamFix {
 
   @Override
   PsiElement migrate(@NotNull Project project,
-               @NotNull ProblemDescriptor descriptor,
-               @NotNull PsiForeachStatement foreachStatement,
-               @NotNull PsiExpression iteratedValue,
-               @NotNull PsiStatement body,
-               @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
+                     @NotNull PsiLoopStatement loopStatement,
+                     @NotNull PsiStatement body,
+                     @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
     PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
+    StringBuilder builder = generateStream(tb.getLastOperation());
     if(tb.getSingleStatement() instanceof PsiReturnStatement) {
       PsiReturnStatement returnStatement = (PsiReturnStatement)tb.getSingleStatement();
       PsiExpression value = returnStatement.getReturnValue();
       if (ExpressionUtils.isLiteral(value, Boolean.TRUE) || ExpressionUtils.isLiteral(value, Boolean.FALSE)) {
         boolean foundResult = (boolean)((PsiLiteralExpression)value).getValue();
-        PsiReturnStatement nextReturnStatement = StreamApiMigrationInspection.getNextReturnStatement(foreachStatement);
+        PsiReturnStatement nextReturnStatement = StreamApiMigrationInspection.getNextReturnStatement(loopStatement);
         if (nextReturnStatement != null) {
           PsiExpression returnValue = nextReturnStatement.getReturnValue();
           if(returnValue == null) return null;
           String methodName = foundResult ? "anyMatch" : "noneMatch";
-          String streamText = generateStream(iteratedValue, tb.getLastOperation()).toString();
-          streamText = addTerminalOperation(streamText, methodName, foreachStatement, tb);
-          restoreComments(foreachStatement, body);
-          if (nextReturnStatement.getParent() == foreachStatement.getParent()) {
+          String streamText = addTerminalOperation(builder.toString(), methodName, loopStatement, tb);
+          restoreComments(loopStatement, body);
+          if (nextReturnStatement.getParent() == loopStatement.getParent()) {
             if(!ExpressionUtils.isLiteral(returnValue, !foundResult)) {
               streamText+= (foundResult ? "||" : "&&") + ParenthesesUtils.getText(returnValue, ParenthesesUtils.AND_PRECEDENCE);
             }
-            removeLoop(foreachStatement);
+            removeLoop(loopStatement);
             return returnValue.replace(elementFactory.createExpressionFromText(streamText, nextReturnStatement));
           }
-          return foreachStatement.replace(elementFactory.createStatementFromText("return " + streamText + ";", foreachStatement));
+          return loopStatement.replace(elementFactory.createStatementFromText("return " + streamText + ";", loopStatement));
         }
       }
     }
     PsiStatement[] statements = tb.getStatements();
-    if (!(statements.length == 1 || (statements.length == 2 && ControlFlowUtils.statementBreaksLoop(statements[1], foreachStatement)))) {
+    if (!(statements.length == 1 || (statements.length == 2 && ControlFlowUtils.statementBreaksLoop(statements[1], loopStatement)))) {
       return null;
     }
-    restoreComments(foreachStatement, body);
-    String streamText = generateStream(iteratedValue, tb.getLastOperation()).toString();
-    streamText = addTerminalOperation(streamText, "anyMatch", foreachStatement, tb);
+    restoreComments(loopStatement, body);
+    String streamText = addTerminalOperation(builder.toString(), "anyMatch", loopStatement, tb);
     PsiStatement statement = statements[0];
     PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(statement);
     if(assignment != null) {
@@ -96,7 +92,7 @@ class ReplaceWithMatchFix extends MigrateToStreamFix {
         // for(....) if(...) {flag = true; break;}
         PsiVariable var = (PsiVariable)maybeVar;
         PsiExpression initializer = var.getInitializer();
-        InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, foreachStatement);
+        InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, loopStatement);
         if(initializer != null && status != InitializerUsageStatus.UNKNOWN) {
           String replacement;
           if(ExpressionUtils.isLiteral(initializer, Boolean.FALSE) &&
@@ -108,12 +104,12 @@ class ReplaceWithMatchFix extends MigrateToStreamFix {
           } else {
             replacement = streamText + "?" + rValue.getText() + ":" + initializer.getText();
           }
-          return replaceInitializer(foreachStatement, var, initializer, replacement, status);
+          return replaceInitializer(loopStatement, var, initializer, replacement, status);
         }
       }
     }
     String replacement = "if(" + streamText + "){" + statement.getText() + "}";
-    return foreachStatement.replace(elementFactory.createStatementFromText(replacement, foreachStatement));
+    return loopStatement.replace(elementFactory.createStatementFromText(replacement, loopStatement));
   }
 
   private static String addTerminalOperation(String origStream, String methodName, @NotNull PsiElement contextElement,
index 6c83570b1f2cdcb150af820dcef46b506dc356f6..63cf08b98b1133acc8ade5332038033c64740ea5 100644 (file)
@@ -15,7 +15,7 @@
  */
 package com.intellij.codeInspection.streamMigration;
 
-import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.MapOp;
 import com.intellij.openapi.project.Project;
 import com.intellij.psi.*;
 import org.jetbrains.annotations.NotNull;
@@ -33,11 +33,9 @@ class ReplaceWithSumFix extends MigrateToStreamFix {
 
   @Override
   PsiElement migrate(@NotNull Project project,
-               @NotNull ProblemDescriptor descriptor,
-               @NotNull PsiForeachStatement foreachStatement,
-               @NotNull PsiExpression iteratedValue,
-               @NotNull PsiStatement body,
-               @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
+                     @NotNull PsiLoopStatement loopStatement,
+                     @NotNull PsiStatement body,
+                     @NotNull StreamApiMigrationInspection.TerminalBlock tb) {
     PsiAssignmentExpression assignment = tb.getSingleExpression(PsiAssignmentExpression.class);
     if (assignment == null) return null;
     PsiVariable var = StreamApiMigrationInspection.extractAccumulator(assignment);
@@ -50,9 +48,8 @@ class ReplaceWithSumFix extends MigrateToStreamFix {
     if (!type.equals(PsiType.DOUBLE) && !type.equals(PsiType.LONG)) {
       type = PsiType.INT;
     }
-    final StringBuilder builder =
-      generateStream(iteratedValue, new StreamApiMigrationInspection.MapOp(tb.getLastOperation(), addend, tb.getVariable(), type));
+    StringBuilder builder = generateStream(new MapOp(tb.getLastOperation(), addend, tb.getVariable(), type));
     builder.append(".sum()");
-    return replaceWithNumericAddition(project, foreachStatement, var, builder, type);
+    return replaceWithNumericAddition(project, loopStatement, var, builder, type);
   }
 }
index f4fb53ad8339494b6d371279f88a88bc0f4274ee..d84181e062025561a0b700d381c70e859080479a 100644 (file)
@@ -32,6 +32,7 @@ import com.intellij.psi.controlFlow.*;
 import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.psi.search.LocalSearchScope;
 import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.psi.tree.IElementType;
 import com.intellij.psi.util.InheritanceUtil;
 import com.intellij.psi.util.PsiTreeUtil;
 import com.intellij.psi.util.PsiUtil;
@@ -43,6 +44,7 @@ import com.intellij.util.containers.IntArrayList;
 import com.siyeh.ig.psiutils.BoolUtils;
 import com.siyeh.ig.psiutils.ControlFlowUtils;
 import com.siyeh.ig.psiutils.ExpressionUtils;
+import com.siyeh.ig.psiutils.ParenthesesUtils;
 import one.util.streamex.EntryStream;
 import one.util.streamex.StreamEx;
 import org.jetbrains.annotations.Contract;
@@ -123,7 +125,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
   }
 
   static boolean isReferencedInOperations(PsiElement element, TerminalBlock tb) {
-    return ReferencesSearch.search(element, new LocalSearchScope(tb.intermediateExpressions().toArray(PsiElement[]::new)))
+    return ReferencesSearch.search(element, new LocalSearchScope(tb.intermediateAndSourceExpressions().toArray(PsiElement[]::new)))
              .findFirst() != null;
   }
 
@@ -350,7 +352,10 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
     return dependsOnCollection[0];
   }
 
-  private static boolean isTrivial(PsiStatement body, PsiParameter parameter) {
+  @Contract("_, null -> false")
+  private static boolean isTrivial(PsiStatement body, PsiLoopStatement loopStatement) {
+    if(!(loopStatement instanceof PsiForeachStatement)) return false;
+    PsiParameter parameter = ((PsiForeachStatement)loopStatement).getIterationParameter();
     //method reference
     final PsiExpression candidate = new LambdaCanBeMethodReferenceInspection()
       .canBeMethodReferenceProblem(body instanceof PsiBlockStatement ? ((PsiBlockStatement)body).getCodeBlock() : body,
@@ -385,6 +390,27 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
     return consumerClass != null ? psiFacade.getElementFactory().createType(consumerClass, variable.getType()) : null;
   }
 
+  static boolean isVariableSuitableForStream(PsiVariable variable, PsiStatement statement) {
+    PsiElement declaration = variable.getParent();
+    // For-loop initializer is not effectively final, but suitable for stream conversion
+    if(declaration instanceof PsiDeclarationStatement) {
+      PsiElement grandParent = declaration.getParent();
+      if (grandParent instanceof PsiForStatement) {
+        PsiForStatement forStatement = (PsiForStatement)grandParent;
+        if (forStatement.getInitialization() == declaration) {
+          PsiStatement body = forStatement.getBody();
+          if(body != null && PsiTreeUtil.isAncestor(statement, body, false)) {
+            return ReferencesSearch.search(variable, new LocalSearchScope(body)).forEach(ref -> {
+              PsiElement element = ref.getElement();
+              return !(element instanceof PsiExpression) || !PsiUtil.isAccessedForWriting((PsiExpression)element);
+            });
+          }
+        }
+      }
+    }
+    return HighlightControlFlowUtil.isEffectivelyFinal(variable, statement, null);
+  }
+
   @Contract("null -> null")
   static PsiLocalVariable extractCollectionVariable(PsiExpression qualifierExpression) {
     if (qualifierExpression instanceof PsiReferenceExpression) {
@@ -465,26 +491,22 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
     @Override
     public void visitForeachStatement(PsiForeachStatement statement) {
       super.visitForeachStatement(statement);
-      final PsiExpression iteratedValue = statement.getIteratedValue();
+      processLoop(statement);
+    }
+
+    @Override
+    public void visitForStatement(PsiForStatement statement) {
+      super.visitForStatement(statement);
+      processLoop(statement);
+    }
+
+    void processLoop(PsiLoopStatement statement) {
       final PsiStatement body = statement.getBody();
-      if (iteratedValue == null || body == null) return;
-
-      final PsiType iteratedValueType = iteratedValue.getType();
-      final PsiClass iteratorClass = PsiUtil.resolveClassInClassTypeOnly(iteratedValueType);
-      PsiClass collectionClass = null;
-      final boolean isArray;
-      if(iteratedValueType instanceof PsiArrayType) {
-        if(!isSupported(((PsiArrayType)iteratedValueType).getComponentType())) return;
-        isArray = true;
-      } else {
-        collectionClass = JavaPsiFacade.getInstance(body.getProject()).findClass(CommonClassNames.JAVA_UTIL_COLLECTION, statement.getResolveScope());
-        if (collectionClass != null && InheritanceUtil.isInheritorOrSelf(iteratorClass, collectionClass, true)) {
-          isArray = false;
-        } else return;
-      }
+      if(body == null) return;
+      StreamSource source = StreamSource.tryCreate(statement);
+      if(source == null) return;
       if (!ExceptionUtil.getThrownCheckedExceptions(body).isEmpty()) return;
-
-      TerminalBlock tb = TerminalBlock.from(statement.getIterationParameter(), body);
+      TerminalBlock tb = TerminalBlock.from(source, body);
       if(tb.isEmpty()) return;
 
       final ControlFlow controlFlow;
@@ -502,7 +524,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
       int startOffset = controlFlow.getStartOffset(body);
       int endOffset = controlFlow.getEndOffset(body);
       final List<PsiVariable> nonFinalVariables = StreamEx.of(ControlFlowUtil.getUsedVariables(controlFlow, startOffset, endOffset))
-        .remove(variable -> HighlightControlFlowUtil.isEffectivelyFinal(variable, body, null)).toList();
+        .remove(variable -> isVariableSuitableForStream(variable, statement)).toList();
 
       if (exitPoints.isEmpty()) {
         if(getIncrementedVariable(tb, nonFinalVariables) != null) {
@@ -514,8 +536,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
         if(!nonFinalVariables.isEmpty()) {
           return;
         }
-        if ((isArray || !isRawSubstitution(iteratedValueType, collectionClass)) && isCollectCall(tb)) {
-          boolean addAll = !tb.hasOperations() && isAddAllCall(tb);
+        if (isCollectCall(tb)) {
+          boolean addAll = statement instanceof PsiForeachStatement && !tb.hasOperations() && isAddAllCall(tb);
           String methodName;
           if(addAll) {
             methodName = "addAll";
@@ -535,7 +557,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
         }
         // do not replace for(T e : arr) {} with Arrays.stream(arr).forEach(e -> {}) even if flag is set
         else if (SUGGEST_FOREACH &&
-                 (tb.hasOperations() || (!isArray && (REPLACE_TRIVIAL_FOREACH || !isTrivial(body, statement.getIterationParameter()))))) {
+                 (tb.hasOperations() || (!(source instanceof ArrayStream) && (REPLACE_TRIVIAL_FOREACH || !isTrivial(body, statement))))) {
           ReplaceWithForeachCallFix forEachFix = new ReplaceWithForeachCallFix("forEach");
           LocalQuickFix[] fixes = {forEachFix};
           if (tb.hasOperations()) { //for .stream()
@@ -548,8 +570,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
         if (nonFinalVariables.isEmpty() && tb.getSingleStatement() instanceof PsiReturnStatement) {
           handleSingleReturn(statement, tb);
         }
-        // Intermediate ops should not refer to non-final variables
-        if (tb.intermediateExpressions()
+        // Source and intermediate ops should not refer to non-final variables
+        if (tb.intermediateAndSourceExpressions()
           .flatCollection(expr -> PsiTreeUtil.collectElementsOfType(expr, PsiReferenceExpression.class))
           .map(PsiReferenceExpression::resolve).anyMatch(nonFinalVariables::contains)) {
           return;
@@ -561,7 +583,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
             return;
           }
           if (ReferencesSearch.search(tb.getVariable(), new LocalSearchScope(statements)).findFirst() == null
-            && exitPoints.size() == 1 && exitPoints.contains(breakStatement)) {
+              && exitPoints.size() == 1 && exitPoints.contains(breakStatement)) {
             registerProblem(statement, "anyMatch", new ReplaceWithMatchFix("anyMatch"));
             return;
           }
@@ -583,14 +605,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
       }
     }
 
-    boolean canCollect(PsiForeachStatement statement, PsiMethodCallExpression methodCallExpression) {
+    boolean canCollect(PsiLoopStatement statement, PsiMethodCallExpression methodCallExpression) {
       if(methodCallExpression == null) return false;
       PsiLocalVariable variable = extractCollectionVariable(methodCallExpression.getMethodExpression().getQualifierExpression());
       if(variable == null) return false;
       return getInitializerUsageStatus(variable, statement) != UNKNOWN;
     }
 
-    void handleSingleReturn(PsiForeachStatement statement, TerminalBlock tb) {
+    void handleSingleReturn(PsiLoopStatement statement, TerminalBlock tb) {
       PsiReturnStatement returnStatement = (PsiReturnStatement)tb.getSingleStatement();
       PsiExpression value = returnStatement.getReturnValue();
       PsiReturnStatement nextReturnStatement = getNextReturnStatement(statement);
@@ -616,7 +638,10 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
       }
       if (!isVariableReferenced(tb.getVariable(), value)) {
         Operation lastOp = tb.getLastOperation();
-        if(!REPLACE_TRIVIAL_FOREACH && lastOp == null || (lastOp instanceof FilterOp && lastOp.getPreviousOp() == null)) return;
+        if (!REPLACE_TRIVIAL_FOREACH && lastOp instanceof StreamSource ||
+            (lastOp instanceof FilterOp && lastOp.getPreviousOp() instanceof StreamSource)) {
+          return;
+        }
         registerProblem(statement, "anyMatch", new ReplaceWithMatchFix("anyMatch"));
       }
       if(nextReturnStatement != null && ExpressionUtils.isSimpleExpression(nextReturnStatement.getReturnValue())
@@ -625,13 +650,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
       }
     }
 
-    private boolean isRawSubstitution(PsiType iteratedValueType, PsiClass collectionClass) {
-      return iteratedValueType instanceof PsiClassType && PsiUtil
-        .isRawSubstitutor(collectionClass, TypeConversionUtil.getSuperClassSubstitutor(collectionClass, (PsiClassType)iteratedValueType));
-    }
-
     @NotNull
-    private TextRange getRange(PsiForeachStatement statement) {
+    private TextRange getRange(PsiLoopStatement statement) {
       boolean wholeStatement = false;
       if(myIsOnTheFly) {
         if (myKey == null) {
@@ -643,18 +663,28 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
           wholeStatement = HighlightDisplayLevel.DO_NOT_SHOW.equals(level);
         }
       }
-      PsiExpression iteratedValue = statement.getIteratedValue();
-      LOG.assertTrue(iteratedValue != null);
-      PsiJavaToken rParenth = statement.getRParenth();
-      if(wholeStatement && rParenth != null) {
-        return new TextRange(statement.getTextOffset(), rParenth.getTextOffset() + 1);
+      if(statement instanceof PsiForeachStatement) {
+        PsiJavaToken rParenth = ((PsiForeachStatement)statement).getRParenth();
+        if (wholeStatement && rParenth != null) {
+          return new TextRange(statement.getTextOffset(), rParenth.getTextOffset() + 1);
+        }
+        PsiExpression iteratedValue = ((PsiForeachStatement)statement).getIteratedValue();
+        LOG.assertTrue(iteratedValue != null);
+        return iteratedValue.getTextRange();
+      } else if(statement instanceof PsiForStatement) {
+        PsiJavaToken rParenth = ((PsiForStatement)statement).getRParenth();
+        if (wholeStatement && rParenth != null) {
+          return new TextRange(statement.getTextOffset(), rParenth.getTextOffset() + 1);
+        }
+        PsiStatement initialization = ((PsiForStatement)statement).getInitialization();
+        LOG.assertTrue(initialization != null);
+        return initialization.getTextRange();
+      } else {
+        throw new IllegalStateException("Unexpected statement type: "+statement);
       }
-      return iteratedValue.getTextRange();
     }
 
-    private void registerProblem(PsiForeachStatement statement, String methodName, LocalQuickFix... fixes) {
-      PsiExpression iteratedValue = statement.getIteratedValue();
-      LOG.assertTrue(iteratedValue != null);
+    private void registerProblem(PsiLoopStatement statement, String methodName, LocalQuickFix... fixes) {
       myHolder.registerProblem(statement, getRange(statement).shiftRight(-statement.getTextOffset()),
                                "Can be replaced with '" + methodName + "' call", fixes);
     }
@@ -700,7 +730,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
   }
 
   @Nullable
-  static PsiMethodCallExpression extractToArrayExpression(PsiForeachStatement statement, PsiMethodCallExpression expression) {
+  static PsiMethodCallExpression extractToArrayExpression(PsiLoopStatement statement, PsiMethodCallExpression expression) {
     // return collection.toArray() or collection.toArray(new Type[0]) or collection.toArray(new Type[collection.size()]);
     PsiElement nextElement = PsiTreeUtil.skipSiblingsForward(statement, PsiComment.class, PsiWhiteSpace.class);
     PsiExpression toArrayCandidate;
@@ -799,7 +829,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
       return StreamEx.of(myExpression);
     }
 
-    abstract String createReplacement(PsiElementFactory factory);
+    abstract String createReplacement();
   }
 
   static class FilterOp extends Operation {
@@ -815,7 +845,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
     }
 
     @Override
-    public String createReplacement(PsiElementFactory factory) {
+    public String createReplacement() {
+      PsiElementFactory factory = JavaPsiFacade.getElementFactory(myExpression.getProject());
       PsiExpression intermediate = makeIntermediateExpression(factory);
       PsiExpression expression =
         myNegated ? factory.createExpressionFromText(BoolUtils.getNegatedExpressionText(intermediate), myExpression) : intermediate;
@@ -858,7 +889,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
     }
 
     @Override
-    public String createReplacement(PsiElementFactory factory) {
+    public String createReplacement() {
       if (isIdentityMapping(myVariable, myExpression)) {
         if (!(myType instanceof PsiPrimitiveType)) {
           return myVariable.getType() instanceof PsiPrimitiveType ? ".boxed()" : "";
@@ -894,20 +925,33 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
 
   static class FlatMapOp extends Operation {
     private final PsiLoopStatement myLoop;
+    private final StreamSource mySource;
 
-    FlatMapOp(@Nullable Operation previousOp, PsiExpression expression, PsiVariable variable, PsiLoopStatement loop) {
-      super(previousOp, expression, variable);
+    FlatMapOp(@Nullable Operation previousOp, StreamSource source, PsiVariable variable, PsiLoopStatement loop) {
+      super(previousOp, source.getExpression(), variable);
       myLoop = loop;
+      mySource = source;
     }
 
     @Override
-    public String createReplacement(PsiElementFactory factory) {
-      return ".flatMap(" + myVariable.getName() + " -> " + getStreamExpression() + ")";
+    public String createReplacement() {
+      String operation = "flatMap";
+      PsiType type = mySource.getVariable().getType();
+      if(type instanceof PsiPrimitiveType && !type.equals(myVariable.getType())) {
+        if(type.equals(PsiType.INT)) {
+          operation = "flatMapToInt";
+        } else if(type.equals(PsiType.LONG)) {
+          operation = "flatMapToLong";
+        } else if(type.equals(PsiType.DOUBLE)) {
+          operation = "flatMapToDouble";
+        }
+      }
+      return "." + operation + "(" + myVariable.getName() + " -> " + getStreamExpression() + ")";
     }
 
     @NotNull
     String getStreamExpression() {
-      return myExpression.getText() + ".stream()";
+      return mySource.createReplacement();
     }
 
     boolean breaksMe(PsiBreakStatement statement) {
@@ -915,35 +959,155 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
     }
   }
 
-  static class ArrayFlatMapOp extends FlatMapOp {
-    ArrayFlatMapOp(@Nullable Operation previousOp, PsiExpression expression, PsiVariable variable, PsiLoopStatement loop) {
-      super(previousOp, expression, variable, loop);
+  abstract static class StreamSource extends Operation {
+    protected StreamSource(PsiVariable variable, PsiExpression expression) {
+      super(null, expression, variable);
     }
 
-    @Override
-    public String createReplacement(PsiElementFactory factory) {
-      String operation = "flatMap";
-      PsiType type = myExpression.getType();
-      if(type instanceof PsiArrayType) {
-        PsiType componentType = ((PsiArrayType)type).getComponentType();
-        if(componentType instanceof PsiPrimitiveType) {
-          if(componentType.equals(PsiType.INT)) {
-            operation = "flatMapToInt";
-          } else if(componentType.equals(PsiType.LONG)) {
-            operation = "flatMapToLong";
-          } else if(componentType.equals(PsiType.DOUBLE)) {
-            operation = "flatMapToDouble";
-          }
-        }
+    @Contract("null -> null")
+    static StreamSource tryCreate(PsiLoopStatement statement) {
+      if(statement instanceof PsiForStatement) {
+        return CountingLoop.from((PsiForStatement)statement);
       }
-      return "." + operation + "(" + myVariable.getName() + " -> " + getStreamExpression() + ")";
+      if(statement instanceof PsiForeachStatement) {
+        ArrayStream source = ArrayStream.from((PsiForeachStatement)statement);
+        return source == null ? CollectionStream.from((PsiForeachStatement)statement) : source;
+      }
+      return null;
+    }
+  }
+
+  static class ArrayStream extends StreamSource {
+    private ArrayStream(PsiVariable variable, PsiExpression expression) {
+      super(variable, expression);
     }
 
     @Override
-    @NotNull
-    String getStreamExpression() {
+    String createReplacement() {
       return "java.util.Arrays.stream("+myExpression.getText() + ")";
     }
+
+    @Nullable
+    public static ArrayStream from(PsiForeachStatement statement) {
+      PsiExpression iteratedValue = statement.getIteratedValue();
+      if (iteratedValue == null) return null;
+
+      PsiType iteratedValueType = iteratedValue.getType();
+      PsiParameter parameter = statement.getIterationParameter();
+
+      if (!(iteratedValueType instanceof PsiArrayType) ||
+          !isSupported(((PsiArrayType)iteratedValueType).getComponentType()) ||
+          ((parameter.getType() instanceof PsiPrimitiveType) &&
+           !parameter.getType().equals(((PsiArrayType)iteratedValueType).getComponentType()))) {
+        return null;
+      }
+
+      return new ArrayStream(parameter, iteratedValue);
+    }
+  }
+
+  static class CollectionStream extends StreamSource {
+
+    private CollectionStream(PsiVariable variable, PsiExpression expression) {
+      super(variable, expression);
+    }
+
+    @Override
+    String createReplacement() {
+      return ParenthesesUtils.getText(myExpression, ParenthesesUtils.POSTFIX_PRECEDENCE) + ".stream()";
+    }
+
+    @Contract("null, _ -> false")
+    static boolean isRawSubstitution(PsiType iteratedValueType, PsiClass collectionClass) {
+      return iteratedValueType instanceof PsiClassType && PsiUtil
+        .isRawSubstitutor(collectionClass, TypeConversionUtil.getSuperClassSubstitutor(collectionClass, (PsiClassType)iteratedValueType));
+    }
+
+    @Nullable
+    public static CollectionStream from(PsiForeachStatement statement) {
+      PsiExpression iteratedValue = statement.getIteratedValue();
+      if (iteratedValue == null) return null;
+
+      PsiType iteratedValueType = iteratedValue.getType();
+      PsiClass collectionClass =
+        JavaPsiFacade.getInstance(statement.getProject()).findClass(CommonClassNames.JAVA_UTIL_COLLECTION, statement.getResolveScope());
+      PsiClass iteratorClass = PsiUtil.resolveClassInClassTypeOnly(iteratedValueType);
+      if (collectionClass == null ||
+          !InheritanceUtil.isInheritorOrSelf(iteratorClass, collectionClass, true) ||
+          isRawSubstitution(iteratedValueType, collectionClass)) {
+        return null;
+      }
+      return new CollectionStream(statement.getIterationParameter(), iteratedValue);
+    }
+  }
+
+  static class CountingLoop extends StreamSource {
+    final PsiExpression myBound;
+    final boolean myIncluding;
+
+    private CountingLoop(PsiLocalVariable counter, PsiExpression initializer, PsiExpression bound, boolean including) {
+      super(counter, initializer);
+      myBound = bound;
+      myIncluding = including;
+    }
+
+    @Override
+    StreamEx<PsiExpression> expressions() {
+      return StreamEx.of(myExpression, myBound);
+    }
+
+    @Override
+    public String createReplacement() {
+      String className = myVariable.getType().equals(PsiType.LONG) ? "java.util.stream.LongStream" : "java.util.stream.IntStream";
+      String methodName = myIncluding ? "rangeClosed" : "range";
+      return className+"."+methodName+"("+myExpression.getText()+", "+myBound.getText()+")";
+    }
+
+    @Nullable
+    public static CountingLoop from(PsiForStatement forStatement) {
+      // check that initialization is for(int/long i = <initial_value>;...;...)
+      if(!(forStatement.getInitialization() instanceof PsiDeclarationStatement)) return null;
+      PsiDeclarationStatement initialization = (PsiDeclarationStatement)forStatement.getInitialization();
+      if(initialization.getDeclaredElements().length != 1) return null;
+      PsiElement declaration = initialization.getDeclaredElements()[0];
+      if(!(declaration instanceof PsiLocalVariable)) return null;
+      PsiLocalVariable counter = (PsiLocalVariable)declaration;
+      if(!counter.getType().equals(PsiType.INT) && !counter.getType().equals(PsiType.LONG)) return null;
+
+      PsiExpression initializer = counter.getInitializer();
+      if(initializer == null) return null;
+
+      // check that increment is like for(...;...;i++)
+      if(!(forStatement.getUpdate() instanceof PsiExpressionStatement)) return null;
+      PsiExpression lValue = extractIncrementedLValue(((PsiExpressionStatement)forStatement.getUpdate()).getExpression());
+      if(!(lValue instanceof PsiReferenceExpression) || ((PsiReferenceExpression)lValue).resolve() != counter) return null;
+
+      // check that condition is like for(...;i<bound;...) or for(...;i<=bound;...)
+      if(!(forStatement.getCondition() instanceof PsiBinaryExpression)) return null;
+      PsiBinaryExpression condition = (PsiBinaryExpression)forStatement.getCondition();
+      IElementType type = condition.getOperationTokenType();
+      boolean closed = false;
+      PsiExpression bound;
+      PsiExpression ref;
+      if(type.equals(JavaTokenType.LE)) {
+        bound = condition.getROperand();
+        ref = condition.getLOperand();
+        closed = true;
+      } else if(type.equals(JavaTokenType.LT)) {
+        bound = condition.getROperand();
+        ref = condition.getLOperand();
+      } else if(type.equals(JavaTokenType.GE)) {
+        bound = condition.getLOperand();
+        ref = condition.getROperand();
+        closed = true;
+      } else if(type.equals(JavaTokenType.GT)) {
+        bound = condition.getLOperand();
+        ref = condition.getROperand();
+      } else return null;
+      if(bound == null || !(ref instanceof PsiReferenceExpression) || ((PsiReferenceExpression)ref).resolve() != counter) return null;
+      if(!TypeConversionUtil.areTypesAssignmentCompatible(counter.getType(), bound)) return null;
+      return new CountingLoop(counter, initializer, bound, closed);
+    }
   }
 
   /**
@@ -952,11 +1116,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
    * some intermediate operations extracted.
    */
   static class TerminalBlock {
-    private final @Nullable Operation myPreviousOp;
+    private final @NotNull Operation myPreviousOp;
     private final @NotNull PsiVariable myVariable;
     private final @NotNull PsiStatement[] myStatements;
 
-    private TerminalBlock(@Nullable Operation previousOp, @NotNull PsiVariable variable, @NotNull PsiStatement... statements) {
+    // At least one previous operation is present (stream source)
+    private TerminalBlock(@NotNull Operation previousOp, @NotNull PsiVariable variable, @NotNull PsiStatement... statements) {
       myVariable = variable;
       while(true) {
         if(statements.length == 1 && statements[0] instanceof PsiBlockStatement) {
@@ -1052,46 +1217,32 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
       TerminalBlock withFilter = extractFilter();
       if(withFilter != null) return withFilter;
       // extract flatMap
-      if(getSingleStatement() instanceof PsiForeachStatement) {
-        // flatMapping of primitive variable is not supported yet
-        if(myVariable.getType() instanceof PsiPrimitiveType) return null;
-        PsiForeachStatement foreachStatement = (PsiForeachStatement)getSingleStatement();
-        final PsiExpression iteratedValue = foreachStatement.getIteratedValue();
-        final PsiStatement body = foreachStatement.getBody();
-        if (iteratedValue != null && body != null) {
-          final PsiType iteratedValueType = iteratedValue.getType();
-          FlatMapOp op = null;
-          if(iteratedValueType instanceof PsiArrayType) {
-            if (!isSupported(((PsiArrayType)iteratedValueType).getComponentType())) return null;
-            op = new ArrayFlatMapOp(myPreviousOp, iteratedValue, myVariable, foreachStatement);
-          } else {
-            final PsiClass iteratorClass = PsiUtil.resolveClassInClassTypeOnly(iteratedValueType);
-            final PsiClass collectionClass =
-              JavaPsiFacade.getInstance(body.getProject())
-                .findClass(CommonClassNames.JAVA_UTIL_COLLECTION, foreachStatement.getResolveScope());
-            if (collectionClass != null && InheritanceUtil.isInheritorOrSelf(iteratorClass, collectionClass, true)) {
-              op = new FlatMapOp(myPreviousOp, iteratedValue, myVariable, foreachStatement);
-            }
-          }
-          if(op != null) {
-            TerminalBlock withFlatMap = new TerminalBlock(op, foreachStatement.getIterationParameter(), body);
-            if(ReferencesSearch.search(myVariable, new LocalSearchScope(body)).findFirst() == null) {
-              return withFlatMap;
-            } else {
-              // Try extract nested filter like this:
-              // for(List subList : list) for(T t : subList) if(condition.test(t)) { ...; break; }
-              // if t is not used in "...", then this could be converted to
-              // list.stream().filter(subList -> subList.stream().anyMatch(condition)).forEach(subList -> ...)
-              TerminalBlock withFlatMapFilter = withFlatMap.extractFilter();
-              if(withFlatMapFilter != null && !withFlatMapFilter.isEmpty()) {
-                PsiStatement[] statements = withFlatMapFilter.getStatements();
-                PsiStatement lastStatement = statements[statements.length-1];
-                if (lastStatement instanceof PsiBreakStatement && op.breaksMe((PsiBreakStatement)lastStatement) &&
-                    ReferencesSearch.search(withFlatMapFilter.getVariable(), new LocalSearchScope(statements)).findFirst() == null) {
-                  return new TerminalBlock(new CompoundFilterOp((FilterOp)withFlatMapFilter.getLastOperation(), op),
-                                           myVariable, Arrays.copyOfRange(statements, 0, statements.length-1));
-                }
-              }
+      if(getSingleStatement() instanceof PsiLoopStatement) {
+        PsiLoopStatement loopStatement = (PsiLoopStatement)getSingleStatement();
+        StreamSource source = StreamSource.tryCreate(loopStatement);
+        final PsiStatement body = loopStatement.getBody();
+        if(source == null || body == null) return null;
+        // flatMap from primitive to primitive is supported only if primitive types match
+        // otherwise it would be necessary to create bogus step like
+        // .mapToObj(var -> blahblah.stream()).flatMap(Function.identity())
+        if(myVariable.getType() instanceof PsiPrimitiveType && !myVariable.getType().equals(source.getVariable().getType())) return null;
+        FlatMapOp op = new FlatMapOp(myPreviousOp, source, myVariable, loopStatement);
+        TerminalBlock withFlatMap = new TerminalBlock(op, source.getVariable(), body);
+        if(ReferencesSearch.search(myVariable, new LocalSearchScope(body)).findFirst() == null) {
+          return withFlatMap;
+        } else {
+          // Try extract nested filter like this:
+          // for(List subList : list) for(T t : subList) if(condition.test(t)) { ...; break; }
+          // if t is not used in "...", then this could be converted to
+          // list.stream().filter(subList -> subList.stream().anyMatch(condition)).forEach(subList -> ...)
+          TerminalBlock withFlatMapFilter = withFlatMap.extractFilter();
+          if(withFlatMapFilter != null && !withFlatMapFilter.isEmpty()) {
+            PsiStatement[] statements = withFlatMapFilter.getStatements();
+            PsiStatement lastStatement = statements[statements.length-1];
+            if (lastStatement instanceof PsiBreakStatement && op.breaksMe((PsiBreakStatement)lastStatement) &&
+                ReferencesSearch.search(withFlatMapFilter.getVariable(), new LocalSearchScope(statements)).findFirst() == null) {
+              return new TerminalBlock(new CompoundFilterOp((FilterOp)withFlatMapFilter.getLastOperation(), op),
+                                       myVariable, Arrays.copyOfRange(statements, 0, statements.length-1));
             }
           }
         }
@@ -1121,7 +1272,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
       return null;
     }
 
-    @Nullable
+    @NotNull
     public Operation getLastOperation() {
       return myPreviousOp;
     }
@@ -1141,7 +1292,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
     }
 
     public boolean hasOperations() {
-      return myPreviousOp != null;
+      return !(myPreviousOp instanceof StreamSource);
     }
 
     public boolean isEmpty() {
@@ -1163,6 +1314,13 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
      * @return stream of physical expressions used in intermediate operations in arbitrary order
      */
     public StreamEx<PsiExpression> intermediateExpressions() {
+      return operations().remove(StreamSource.class::isInstance).flatMap(Operation::expressions);
+    }
+
+    /**
+     * @return stream of physical expressions used in stream source and intermediate operations in arbitrary order
+     */
+    public StreamEx<PsiExpression> intermediateAndSourceExpressions() {
       return operations().flatMap(Operation::expressions);
     }
 
@@ -1184,8 +1342,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
     }
 
     @NotNull
-    public static TerminalBlock from(PsiVariable variable, PsiStatement statement) {
-      return new TerminalBlock(null, variable, statement).extractOperations();
+    public static TerminalBlock from(StreamSource source, PsiStatement body) {
+      return new TerminalBlock(source, source.myVariable, body).extractOperations();
     }
   }
 }
index 429487ca4e52d8d9d089387c713f8d1ff3cbe66f..ebc24ac743f7d92d57d24b21b9ce20a00cf7bf05 100644 (file)
@@ -52,7 +52,7 @@ public class CreateModuleInfoAction extends CreateFromTemplateActionBase {
     DataContext ctx = e.getDataContext();
     boolean available = Optional.ofNullable(LangDataKeys.IDE_VIEW.getData(ctx))
       .map(view -> getTargetDirectory(ctx, view))
-      .filter(dir -> JavaDirectoryService.getInstance().isSourceRoot(dir) && PsiUtil.isLanguageLevel9OrHigher(dir))
+      .filter(PsiUtil::isLanguageLevel9OrHigher)
       .map(ModuleUtilCore::findModuleForPsiElement)
       .map(module -> FilenameIndex.getVirtualFilesByName(module.getProject(), MODULE_INFO_FILE, module.getModuleScope(false)).isEmpty())
       .orElse(false);
@@ -63,7 +63,15 @@ public class CreateModuleInfoAction extends CreateFromTemplateActionBase {
   @Override
   protected PsiDirectory getTargetDirectory(DataContext dataContext, IdeView view) {
     PsiDirectory[] directories = view.getDirectories();
-    return directories.length == 1 ? directories[0] : null;
+    if (directories.length == 1) {
+      PsiDirectory directory = directories[0];
+      JavaDirectoryService service = JavaDirectoryService.getInstance();
+      if (service.isSourceRoot(directory) && service.getPackage(directory) != null) {
+        return directory;
+      }
+    }
+
+    return null;
   }
 
   @Override
index 9d192a1fecb4caa3d8938d4da81e5b6f3ce0f1c0..b96d77cac98f6e83cd5c1bc17a34565c0323072e 100644 (file)
@@ -107,16 +107,15 @@ public class JavadocHelper {
     }
 
     final CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getInstance(psiFile.getProject()).getCurrentSettings();
-    final int indentSize = codeStyleSettings.getIndentSize(psiFile.getFileType());
     int column;
     if (codeStyleSettings.JD_ALIGN_PARAM_COMMENTS) {
       column = Math.max(descriptionStartColumn, parameterNameEndColumn);
       if (column <= parameterNameEndColumn) {
-        column = parameterNameEndColumn + indentSize;
+        column = parameterNameEndColumn + 1;
       }
     }
     else {
-      column = anchor.parameterNameEndPosition.column + indentSize;
+      column = anchor.parameterNameEndPosition.column + 1;
     }
     return new LogicalPosition(anchor.parameterNameEndPosition.line, column);
   }
index 0bd0175a12858c5977e8363cd03c316254246f72..5dc87efce4fd2873ece613e447f64dee9fba1ad6 100644 (file)
@@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.fileTypes.FileType;
 import com.intellij.openapi.fileTypes.FileTypeManager;
 import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.roots.ProjectRootManager;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.JavaDirectoryService;
@@ -40,7 +41,7 @@ public class PsiJavaDirectoryImpl extends PsiDirectoryImpl {
   @Override
   public void checkCreateFile(@NotNull final String name) throws IncorrectOperationException {
     final FileType type = FileTypeManager.getInstance().getFileTypeByFileName(name);
-    if (type == StdFileTypes.CLASS) {
+    if (type == StdFileTypes.CLASS && ProjectRootManager.getInstance(getProject()).getFileIndex().isInSource(getVirtualFile())) {
       throw new IncorrectOperationException("Cannot create class-file");
     }
 
index 6a9fbf1fcd2c5fd6837ecae1f7287b92face06c2..6332e22cc7716d9f32aceb54656371038e16f14f 100644 (file)
@@ -161,25 +161,23 @@ public class CopyClassesHandler extends CopyHandlerDelegateBase {
       final PsiFile psiFile = classes.keySet().iterator().next();
       defaultTargetDirectory = psiFile.getContainingDirectory();
       LOG.assertTrue(defaultTargetDirectory != null, psiFile);
-    } else {
-      Project project = defaultTargetDirectory.getProject();
-      VirtualFile sourceRootForFile = ProjectRootManager.getInstance(project).getFileIndex()
-        .getSourceRootForFile(defaultTargetDirectory.getVirtualFile());
-      if (sourceRootForFile == null) {
-        final List<PsiElement> files = new ArrayList<>();
-        for (int i = 0, elementsLength = elements.length; i < elementsLength; i++) {
-          PsiFile containingFile = elements[i].getContainingFile();
-          if (containingFile != null) {
-            files.add(containingFile);
-          } else if (elements[i] instanceof PsiDirectory) {
-            files.add(elements[i]);
-          }
+    }
+    Project project = defaultTargetDirectory.getProject();
+    VirtualFile sourceRootForFile = ProjectRootManager.getInstance(project).getFileIndex().getSourceRootForFile(defaultTargetDirectory.getVirtualFile());
+    if (sourceRootForFile == null) {
+      final List<PsiElement> files = new ArrayList<>();
+      for (PsiElement element : elements) {
+        PsiFile containingFile = element.getContainingFile();
+        if (containingFile != null) {
+          files.add(containingFile);
+        }
+        else if (element instanceof PsiDirectory) {
+          files.add(element);
         }
-        CopyFilesOrDirectoriesHandler.copyAsFiles(files.toArray(new PsiElement[files.size()]), defaultTargetDirectory, project);
-        return;
       }
+      CopyFilesOrDirectoriesHandler.copyAsFiles(files.toArray(new PsiElement[files.size()]), defaultTargetDirectory, project);
+      return;
     }
-    Project project = defaultTargetDirectory.getProject();
     Object targetDirectory = null;
     String className = null;
     boolean openInEditor = true;
index ab130c4105f7d32c1dc60239ee61811de15aa704..fcaf1b8d7d32183cfdb233ff9bd1848ced21e3dd 100644 (file)
@@ -117,7 +117,7 @@ public class OldReferenceResolver {
       final PsiReferenceExpression oldRef = (PsiReferenceExpression)oldExpr;
       final JavaResolveResult adv = oldRef.advancedResolve(false);
       final PsiElement scope = getClassContainingResolve(adv);
-      final PsiElement clss = PsiTreeUtil.getParentOfType(oldExpr, PsiClass.class, PsiLambdaExpression.class);
+      final PsiElement clss = PsiTreeUtil.getParentOfType(oldExpr, PsiClass.class, PsiFunctionalExpression.class);
       if (clss != null && scope != null ) {
 
         final PsiElement subj = adv.getElement();
index 682ed89a091ee0d383030630ddcbacdec9132a6b..8beeebf673c05065ae0fba4aae51b27c6b2ce2cc 100644 (file)
@@ -34,7 +34,6 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URISyntaxException;
 import java.net.URL;
 import java.nio.file.Paths;
 import java.util.ArrayList;
@@ -108,14 +107,7 @@ public class MigrationMapSet {
 
       for (PredefinedMigrationProvider provider : Extensions.getExtensions(PredefinedMigrationProvider.EP_NAME)) {
         URL migrationMap = provider.getMigrationMap();
-        File migrationFile;
-        try {
-          migrationFile = Paths.get(migrationMap.toURI()).toFile();
-        }
-        catch (URISyntaxException e) {
-          migrationFile = new File(migrationMap.getFile());
-        }
-        copyMap(dir, migrationMap, migrationFile.getName());
+        copyMap(dir, migrationMap, new File(migrationMap.getFile()).getName());
       }
 
       for (String defaultTemplate : DEFAULT_MAPS) {
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFlatMapForLoop.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFlatMapForLoop.java
new file mode 100644 (file)
index 0000000..ed773c1
--- /dev/null
@@ -0,0 +1,11 @@
+// "Replace with findFirst()" "true"
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.IntStream;
+
+public class Main {
+  public String testNestedForLoop(int[] data, List<String> info) {
+      return Arrays.stream(data).flatMap(val -> IntStream.rangeClosed(0, val)).mapToObj(info::get).filter(str -> !str.isEmpty()).findFirst().orElse(null);
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterForLoop.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterForLoop.java
new file mode 100644 (file)
index 0000000..6b3a851
--- /dev/null
@@ -0,0 +1,12 @@
+// "Replace with collect" "true"
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class Main {
+  public void testForLoop(List<String> input) {
+      List<Integer> result = IntStream.range(0, 10).mapToObj(i -> input.get(i).length()).collect(Collectors.toList());
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterForLoopBoxed.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterForLoopBoxed.java
new file mode 100644 (file)
index 0000000..770bd8e
--- /dev/null
@@ -0,0 +1,12 @@
+// "Replace with collect" "true"
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class Main {
+  public void testForLoop() {
+      List<Integer> result = IntStream.rangeClosed(0, 10).boxed().collect(Collectors.toList());
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterForLoopShortBound.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterForLoopShortBound.java
new file mode 100644 (file)
index 0000000..553dc81
--- /dev/null
@@ -0,0 +1,14 @@
+// "Replace with collect" "true"
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class Main {
+  public void testForLoop(List<String> input) {
+    List<Integer> result;
+    short s = (short)input.size();
+      result = IntStream.range(0, s).mapToObj(i -> input.get(i).length()).collect(Collectors.toList());
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterPrimitiveArray.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterPrimitiveArray.java
new file mode 100644 (file)
index 0000000..014c665
--- /dev/null
@@ -0,0 +1,8 @@
+import java.util.Arrays;
+
+// "Replace with forEach" "true"
+public class Main {
+  public void test(int[] arr) {
+      Arrays.stream(arr).filter(i -> i > 0).forEach(System.out::println);
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFindFirstUsedInBound.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFindFirstUsedInBound.java
new file mode 100644 (file)
index 0000000..8e8690a
--- /dev/null
@@ -0,0 +1,18 @@
+// "Replace with findFirst()" "false"
+
+public class Main {
+  public boolean check(int value) {
+    return value == 3;
+  }
+
+  public void find() {
+    int end = 10;
+    for(<caret>int i=0; i<end; i++) {
+      if(check(i)) {
+        end = i;
+        break;
+      }
+    }
+    System.out.println(end);
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFlatMapForLoop.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFlatMapForLoop.java
new file mode 100644 (file)
index 0000000..b891bb8
--- /dev/null
@@ -0,0 +1,17 @@
+// "Replace with findFirst()" "true"
+
+import java.util.List;
+
+public class Main {
+  public String testNestedForLoop(int[] data, List<String> info) {
+    for(int val : da<caret>ta) {
+      for(int x = 0; x <= val; x++) {
+        String str = info.get(x);
+        if(!str.isEmpty()) {
+          return str;
+        }
+      }
+    }
+    return null;
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoop.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoop.java
new file mode 100644 (file)
index 0000000..10c9c38
--- /dev/null
@@ -0,0 +1,13 @@
+// "Replace with collect" "true"
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Main {
+  public void testForLoop(List<String> input) {
+    List<Integer> result = new ArrayList<>();
+    for (in<caret>t i = 0; i < 10; i++) {
+      result.add(input.get(i).length());
+    }
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopBoxed.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopBoxed.java
new file mode 100644 (file)
index 0000000..e51f6d3
--- /dev/null
@@ -0,0 +1,13 @@
+// "Replace with collect" "true"
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Main {
+  public void testForLoop() {
+    List<Integer> result = new ArrayList<>();
+    for (in<caret>t i = 0; 10 >= i; i++) {
+      result.add(i);
+    }
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopFloatBound.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopFloatBound.java
new file mode 100644 (file)
index 0000000..97d09fc
--- /dev/null
@@ -0,0 +1,14 @@
+// "Replace with collect" "false"
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Main {
+  public void testForLoop(List<String> input) {
+    List<Integer> result = new ArrayList<>();
+    float s = (float)input.size();
+    for (in<caret>t i = 0; i < s; i++) {
+      result.add(input.get(i).length());
+    }
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopShortBound.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopShortBound.java
new file mode 100644 (file)
index 0000000..18e3815
--- /dev/null
@@ -0,0 +1,14 @@
+// "Replace with collect" "true"
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Main {
+  public void testForLoop(List<String> input) {
+    List<Integer> result = new ArrayList<>();
+    short s = (short)input.size();
+    for (in<caret>t i = 0; i < s; i++) {
+      result.add(input.get(i).length());
+    }
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopUpdated.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopUpdated.java
new file mode 100644 (file)
index 0000000..24ad535
--- /dev/null
@@ -0,0 +1,13 @@
+// "Replace with collect" "false"
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Main {
+  public void testForLoop(List<String> input) {
+    List<Integer> result = new ArrayList<>();
+    for (in<caret>t i = 0; i < 10; i++) {
+      result.add(input.get(i++).length());
+    }
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopWrongBound.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopWrongBound.java
new file mode 100644 (file)
index 0000000..c19b9f9
--- /dev/null
@@ -0,0 +1,13 @@
+// "Replace with collect" "false"
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Main {
+  public void testForLoop(List<String> input) {
+    List<Integer> result = new ArrayList<>();
+    for (in<caret>t i = 0; i > 10; i++) {
+      result.add(input.get(i).length());
+    }
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopWrongIncrement.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopWrongIncrement.java
new file mode 100644 (file)
index 0000000..1c21323
--- /dev/null
@@ -0,0 +1,13 @@
+// "Replace with collect" "false"
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Main {
+  public void testForLoop(List<String> input) {
+    List<Integer> result = new ArrayList<>();
+    for (in<caret>t i = 0; i < 10; i+=2) {
+      result.add(input.get(i).length());
+    }
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopWrongInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeForLoopWrongInitializer.java
new file mode 100644 (file)
index 0000000..021899c
--- /dev/null
@@ -0,0 +1,13 @@
+// "Replace with collect" "false"
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Main {
+  public void testForLoop(List<String> input) {
+    List<Integer> result = new ArrayList<>();
+    for (in<caret>t i = 0, j=0; i < 10; i++) {
+      result.add(input.get(i).length());
+    }
+  }
+}
\ No newline at end of file
index 16a9a198f4c13c7f752f4ed8572c93f5ea8c19e7..1ce9d739ffede640a052c251f77fe934cc342c43 100644 (file)
@@ -1,7 +1,7 @@
-// "Replace with forEach" "false"
+// "Replace with forEach" "true"
 public class Main {
   public void test(int[] arr) {
-    for(int i : arr) {
+    for(int i : a<caret>rr) {
       if(i > 0) {
         System.out.println(i);
       }
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforePrimitiveArrayWrongType.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforePrimitiveArrayWrongType.java
new file mode 100644 (file)
index 0000000..21c93cb
--- /dev/null
@@ -0,0 +1,10 @@
+// "Replace with forEach" "false"
+public class Main {
+  public void test(int[] arr) {
+    for(float i : a<caret>rr) {
+      if(i > 0) {
+        System.out.println(i);
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeSumAccessOuterFor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeSumAccessOuterFor.java
new file mode 100644 (file)
index 0000000..82623b2
--- /dev/null
@@ -0,0 +1,18 @@
+// "Replace with sum()" "false"
+
+import java.util.List;
+
+public class Main {
+  public long testFor(List<List<String>> list) {
+    long count = 0;
+    for (int i = 0; i < list.size(); i++) {
+      for (String s : list.g<caret>et(i)) {
+        String trimmed = s.trim();
+        if (trimmed.isEmpty()) {
+          count += i;
+        }
+      }
+    }
+    return count;
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/projectView/contentRootUnderExcluded/B.txt b/java/java-tests/testData/projectView/contentRootUnderExcluded/B.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/java/java-tests/testData/projectView/contentRootUnderExcluded/exc/excluded.txt b/java/java-tests/testData/projectView/contentRootUnderExcluded/exc/excluded.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/java/java-tests/testData/projectView/contentRootUnderExcluded/exc/gen/A.java b/java/java-tests/testData/projectView/contentRootUnderExcluded/exc/gen/A.java
new file mode 100644 (file)
index 0000000..e69de29
index f294f865fd24968553f93e6ad3f021bcc126380e..2b4a795c944effa53327a40a3ace7d2eb1a6b4c6 100644 (file)
@@ -95,7 +95,7 @@ class Test {
       expected: '''\
 class Test {
     /**
-     * @param i    <caret>
+     * @param i <caret>
      * @param j
      */
     void test(int i, int j) {
@@ -251,7 +251,7 @@ class Test {
       expected: '''\
 class Test {
     /**
-     * @param i    <caret>
+     * @param i <caret>
      */ 
     void test(int i) {
     }
@@ -272,7 +272,7 @@ class Test {
       expected: '''\
 class Test {
     /**
-     * @param i    <caret>
+     * @param i <caret>
      * @param j
      * @param k
      */ 
@@ -399,7 +399,7 @@ class Test<T> {<caret>
 /**
  * My description
  * @author me
- * @param <T>    <caret>
+ * @param <T> <caret>
  */
 class Test<T> {
 }''')
@@ -420,7 +420,7 @@ class Test<T, V> {
  * My description
  * @author me
  * @param <T>    type description
- * @param <V>    <caret>
+ * @param <V> <caret>
  */
 class Test<T, V> {
 }''')
@@ -467,7 +467,7 @@ class Test {
       expected: '''\
 class Test {
     /**
-     * @param i    <caret>
+     * @param i <caret>
      * @param j    
      */
     public void test(int i, int j) {
@@ -491,7 +491,7 @@ class Test {
 class Test {
   /**
    * @param <A>    A description
-   * @param <B>    <caret>
+   * @param <B> <caret>
    */
   <A, B> void test() {
   }
@@ -515,7 +515,7 @@ class Test<A, B> {<caret>
 /**
  * Class description
  * @author Zigmund
- * @param <A>    <caret>
+ * @param <A> <caret>
  * @param <B>    multi-line
  *               description
  */
@@ -575,7 +575,7 @@ class Test {
       expected: '''\
 class Test {
     /**
-     * @param i    <caret>
+     * @param i <caret>
      */ 
     void test(int i) {
     }
index 46fb031dd4bd5fb4e1427e212dbb5b6cf366724b..5eecadf0d209451cf775fa7766509581c563adc9 100644 (file)
@@ -142,20 +142,44 @@ public class ProjectTreeStructureTest extends BaseProjectViewTestCase {
     ModuleManagerImpl.getInstanceImpl(myProject).setModuleGroupPath(module, new String[]{"modules"});
     PsiTestUtil.addContentRoot(module, mainModuleRoot.findFileByRelativePath("src/com/package1/p2/p3"));
 
-    TestProjectTreeStructure structure = new TestProjectTreeStructure(myProject, getTestRootDisposable());
-    structure.setShowLibraryContents(false);
-
-    String structureContent = PlatformTestUtil.print(structure, structure.getRootElement(), 0, null, 10, ' ', myPrintInfo).toString();
-
-    Assert.assertFalse(structureContent.contains("modules"));
-    assertEquals("Project\n" +
-                 " noDuplicateModules\n" +
-                 "  src\n" +
-                 "   com\n" +
-                 "    package1\n" +
-                 "     Test.java\n" +
-                 " nested_module.iml\n" +
-                 " testNoDuplicateModules.iml\n",
-                 structureContent);
+    myStructure.setShowLibraryContents(false);
+    myStructure.hideExcludedFiles();
+
+    assertStructureEqual("Project\n" +
+                         " nested_module.iml\n" +
+                         " noDuplicateModules\n" +
+                         "  src\n" +
+                         "   com\n" +
+                         "    package1\n" +
+                         "     Test.java\n" +
+                         " testNoDuplicateModules.iml\n");
+  }
+
+  public void testContentRootUnderExcluded() {
+    VirtualFile mainModuleRoot = ModuleRootManager.getInstance(myModule).getContentRoots()[0];
+
+    PsiTestUtil.addExcludedRoot(myModule, mainModuleRoot.findFileByRelativePath("exc"));
+
+    PsiTestUtil.addContentRoot(myModule, mainModuleRoot.findFileByRelativePath("exc/gen"));
+
+    myStructure.setShowLibraryContents(false);
+
+    assertStructureEqual("Project\n" +
+                         " contentRootUnderExcluded\n" +
+                         "  B.txt\n" +
+                         "  exc\n" +
+                         "   excluded.txt\n" +
+                         "   gen\n" +
+                         "    A.java\n" +
+                         " testContentRootUnderExcluded.iml\n");
+
+    myStructure.hideExcludedFiles();
+    assertStructureEqual("Project\n" +
+                         " Module\n" +
+                         "  contentRootUnderExcluded\n" +
+                         "   B.txt\n" +
+                         "  gen\n" +
+                         "   A.java\n" +
+                         " testContentRootUnderExcluded.iml\n");
   }
 }
index 70fec7bcf19f8edf8975e1c5e3c3d54094322bc0..0c6d1f8fa17d46f753f8b4b7d084690909b56f74 100644 (file)
@@ -65,9 +65,17 @@ public abstract class BaseProjectViewTestCase extends TestSourceBasedTestCase {
     return myStructure;
   }
 
-  private void assertStructureEqual(PsiDirectory root, String expected, int maxRowCount, AbstractTreeStructure structure) {
+  private void assertStructureEqual(PsiDirectory root, String expected, int maxRowCount, AbstractProjectTreeStructure structure) {
     assertNotNull(root);
-    PsiDirectoryNode rootNode = new PsiDirectoryNode(myProject, root, (ViewSettings)structure);
+    PsiDirectoryNode rootNode = new PsiDirectoryNode(myProject, root, structure);
+    assertStructureEqual(expected, maxRowCount, rootNode);
+  }
+
+  protected void assertStructureEqual(String expected) {
+    assertStructureEqual(expected, -1, myStructure.getRootElement());
+  }
+
+  private void assertStructureEqual(String expected, int maxRowCount, Object rootNode) {
     ProjectViewTestUtil.assertStructureEqual(myStructure, expected, maxRowCount, PlatformTestUtil.createComparator(myPrintInfo), rootNode, myPrintInfo);
   }
 
index 3fef298f88191a1846fbf836918638617d099b60..4d21510ad72b7afbc1f02253c4018dbba597e820 100644 (file)
@@ -74,9 +74,6 @@ public class ProjectPaths {
       else if (classpathPart == ClasspathPart.AFTER_JDK) {
         enumerator = enumerator.satisfying(new AfterJavaSdkItemFilter(module));
       }
-      else if (classpathPart == ClasspathPart.MODULE_PATH) {
-        enumerator = enumerator.satisfying(new ModuleSourceElementsFilter());
-      }
       JpsJavaDependenciesRootsEnumerator rootsEnumerator = enumerator.classes();
       if (excludeMainModuleOutput) {
         rootsEnumerator = rootsEnumerator.withoutSelfModuleOutput();
@@ -181,7 +178,7 @@ public class ProjectPaths {
     return StringUtil.isEmpty(sourceDirName)? outputDir : new File(outputDir, sourceDirName);
   }
 
-  private enum ClasspathPart {WHOLE, BEFORE_JDK, AFTER_JDK, MODULE_PATH}
+  private enum ClasspathPart {WHOLE, BEFORE_JDK, AFTER_JDK}
 
   private static class BeforeJavaSdkItemFilter implements Condition<JpsDependencyElement> {
     private JpsModule myModule;
@@ -220,13 +217,4 @@ public class ProjectPaths {
       return mySdkFound;
     }
   }
-
-  private static class ModuleSourceElementsFilter implements Condition<JpsDependencyElement> {
-    private ModuleSourceElementsFilter() { }
-
-    @Override
-    public boolean value(JpsDependencyElement dependency) {
-      return dependency instanceof JpsModuleDependency || dependency instanceof JpsModuleSourceDependency;
-    }
-  }
 }
\ No newline at end of file
index 5d0ff6cc85c6f789f6cd44dff8d94fbcc9ea08b4..84972eb29617ad30b59e734895b6a7ea608919f2 100644 (file)
@@ -22,6 +22,10 @@ import org.jetbrains.jps.model.artifact.JpsArtifact;
 import java.util.List;
 
 /**
+ * Allows to perform additional tasks when artifacts are built. Implementations of this class are registered as Java services, by creating
+ * a file META-INF/services/org.jetbrains.jps.builders.artifacts.ArtifactBuildTaskProvider containing the qualified name of your
+ * implementation class.
+ *
  * @author nik
  */
 public abstract class ArtifactBuildTaskProvider {
@@ -38,6 +42,13 @@ public abstract class ArtifactBuildTaskProvider {
     }
   }
 
+  /**
+   * Returns list of tasks which need to be executed during {@code buildPhase} when {@code artifact} is building. Firstly tasks returned for
+   * {@link ArtifactBuildPhase#PRE_PROCESSING PRE_PROCESSING} are executed, then files specified in the artifact layout are copied to the output directory.
+   * If all files in the artifact output were up to date, i.e. no copying was performed, the build finishes. Otherwise all tasks returned for
+   * {@link ArtifactBuildPhase#FINISHING_BUILD FINISHING_BUILD} are executed and then all tasks returned for
+   * {@link ArtifactBuildPhase#POST_PROCESSING POST_PROCESSING} are executed.
+   */
   @NotNull
   public abstract List<? extends BuildTask> createArtifactBuildTasks(@NotNull JpsArtifact artifact, @NotNull ArtifactBuildPhase buildPhase);
 }
index 9399e9391b7546d5e8c908bdc65617e786f670d7..373fc7dce30b941c788d0184d4f465fd4aeba6d6 100644 (file)
@@ -900,7 +900,8 @@ int APIENTRY _tWinMain(HINSTANCE hInstance,
     return 0;
   }
 
-  if (!CheckSingleInstance()) return 1;
+  //it's OK to return 0 here, because the control is transferred to the first instance
+  if (!CheckSingleInstance()) return 0;
 
   if (nativesplash = wcsstr(lpCmdLine, _T("/nativesplash")) != NULL) StartSplashProcess();
 
index 22a1c4a067a38ba88ac6ebab2d408646d3272e6c..4df677907bd091a8d57539e18584db9ae79fbf95 100644 (file)
@@ -344,6 +344,10 @@ public class RefManagerImpl extends RefManager {
   public void inspectionReadActionFinished() {
     myIsInProcess = false;
     if (myScope != null) myScope.invalidate();
+
+    synchronized (myRefTable) {
+      mySortedRefs = null;
+    }
   }
 
   public void startOfflineView() {
index 83d0ee6f84fe1e832d7c6adff01f63b2de42be4c..c5c6b29f14eb37173ccf957aebeada4da316b277 100644 (file)
@@ -85,13 +85,6 @@ public class DiffPsiFileType extends LanguageFileType implements FileTypeIdentif
   }
 
 
-  public static class TypeFactory extends FileTypeFactory {
-    @Override
-    public void createFileTypes(@NotNull FileTypeConsumer consumer) {
-      consumer.consume(INSTANCE);
-    }
-  }
-
   public static class Substitutor extends LanguageSubstitutor {
     @Nullable
     @Override
index 9971ef08d351cc88a4db652ed9e9dc27dc9eb785..8172e35d464023ce9b36971d787e60a511befd0b 100644 (file)
@@ -19,9 +19,13 @@ import com.intellij.diff.DiffContext;
 import com.intellij.diff.contents.DiffContent;
 import com.intellij.diff.contents.DocumentContent;
 import com.intellij.diff.util.DiffUtil;
+import com.intellij.ide.DataManager;
 import com.intellij.openapi.editor.EditorFactory;
 import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.fileEditor.FileEditorManager;
 import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.ui.components.panels.Wrapper;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -30,9 +34,19 @@ import java.awt.event.FocusListener;
 
 public class TextEditorHolder extends EditorHolder {
   @NotNull protected final EditorEx myEditor;
+  @NotNull protected final Wrapper myPanel;
 
-  public TextEditorHolder(@NotNull EditorEx editor) {
+  public TextEditorHolder(@Nullable Project project, @NotNull EditorEx editor) {
     myEditor = editor;
+    myPanel = new Wrapper(myEditor.getComponent());
+
+    DataManager.registerDataProvider(myPanel, (dataId) -> {
+      if (project != null && !project.isDisposed() && Registry.is("diff.enable.psi.highlighting")) {
+        final Object o = FileEditorManager.getInstance(project).getData(dataId, editor, editor.getCaretModel().getCurrentCaret());
+        if (o != null) return o;
+      }
+      return null;
+    });
   }
 
   @NotNull
@@ -48,7 +62,7 @@ public class TextEditorHolder extends EditorHolder {
   @NotNull
   @Override
   public JComponent getComponent() {
-    return myEditor.getComponent();
+    return myPanel;
   }
 
   @Override
@@ -70,7 +84,7 @@ public class TextEditorHolder extends EditorHolder {
   public static TextEditorHolder create(@Nullable Project project, @NotNull DocumentContent content) {
     EditorEx editor = DiffUtil.createEditor(content.getDocument(), project, false, true);
     DiffUtil.configureEditor(editor, content, project);
-    return new TextEditorHolder(editor);
+    return new TextEditorHolder(project, editor);
   }
 
   public static class TextEditorHolderFactory extends EditorHolderFactory<TextEditorHolder> {
index d7750be9e7b69f9e4f937c7cfbc056192e3bb6b0..4b97639f734bfb7b2f83e0755a964cf4dd677826 100644 (file)
@@ -354,10 +354,6 @@ public abstract class TwosideTextDiffViewer extends TwosideDiffViewer<TextEditor
   @Override
   public Object getData(@NonNls String dataId) {
     EditorEx editor = getCurrentEditor();
-    if (myProject != null && !myProject.isDisposed() && Registry.is("diff.enable.psi.highlighting")) {
-      final Object o = FileEditorManager.getInstance(myProject).getData(dataId, editor, editor.getCaretModel().getCurrentCaret());
-      if (o != null) return o;
-    }
 
     if (DiffDataKeys.CURRENT_EDITOR.is(dataId)) {
       return editor;
index 43c02ca232d467d0faf6cf6ce1b15457f9a6ab41..d893485682624ecfc776aeff5299f8b01c7c7cd7 100644 (file)
@@ -28,6 +28,10 @@ import java.util.List;
 */
 @Tag("activation")
 public class TaskActivationState {
+  @Tag("before_run")
+  @AbstractCollection(surroundWithTag = false, elementTag = "task", elementValueAttribute = "name")
+  public List<String> beforeRunTasks = new ArrayList<>();
+
   @Tag("before_sync")
   @AbstractCollection(surroundWithTag = false, elementTag = "task", elementValueAttribute = "name")
   public List<String> beforeSyncTasks = new ArrayList<>();
@@ -68,6 +72,8 @@ public class TaskActivationState {
         return beforeCompileTasks;
       case AFTER_SYNC:
         return afterSyncTasks;
+      case BEFORE_RUN:
+        return beforeRunTasks;
       case BEFORE_SYNC:
         return beforeSyncTasks;
       case AFTER_REBUILD:
diff --git a/platform/lang-impl/src/com/intellij/analysis/actions/ToggleInlineHintsAction.kt b/platform/lang-impl/src/com/intellij/analysis/actions/ToggleInlineHintsAction.kt
new file mode 100644 (file)
index 0000000..828e0b2
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.analysis.actions
+
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
+import com.intellij.openapi.fileEditor.FileEditorManager
+import com.intellij.openapi.project.ProjectManager
+import com.intellij.psi.PsiManager
+
+class ToggleInlineHintsAction: AnAction() {
+  
+  override fun update(e: AnActionEvent) {
+    e.presentation.isEnabled = true
+
+    val isShow = EditorSettingsExternalizable.getInstance().isShowParameterNameHints
+    e.presentation.text = if (isShow) "Hide Parameter Name Hints" else "Show Parameter Name Hints"
+  }
+
+  override fun actionPerformed(e: AnActionEvent) {
+    val settings = EditorSettingsExternalizable.getInstance()
+    val before = settings.isShowParameterNameHints
+    settings.isShowParameterNameHints = !before
+    
+    ProjectManager.getInstance().openProjects.forEach {
+      val psiManager = PsiManager.getInstance(it)
+      val daemonCodeAnalyzer = DaemonCodeAnalyzer.getInstance(it)
+      val fileEditorManager = FileEditorManager.getInstance(it)
+      
+      fileEditorManager.selectedFiles.forEach {
+        psiManager.findFile(it)?.let { daemonCodeAnalyzer.restart(it) }
+      }
+    }
+  }
+  
+}
\ No newline at end of file
index 12e2e285122199018bf1b8ff04ba7004e02d5070..6ea9e784118eb456251bd56981a97185acc25e15 100644 (file)
@@ -85,8 +85,9 @@ import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.TimeUnit;
 
 /**
- * @author peter
+ * Please don't use this class directly from plugins
  */
+@Deprecated
 public class CompletionProgressIndicator extends ProgressIndicatorBase implements CompletionProcess, Disposable {
   private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.CompletionProgressIndicator");
   private final Editor myEditor;
index 8763a0fc746eafdb5abbb165387b837fa5b9251b..960557466c6f28b8b8674b6325148bd3bfe9c42f 100644 (file)
@@ -159,6 +159,12 @@ public class ParameterHintsPresentationManager implements Disposable {
       updateState(editor, newText);
     }
 
+    @Nullable
+    @Override
+    public String getContextMenuGroupId() {
+      return "ParameterNameHints";
+    }
+
     private void updateState(Editor editor, String text) {
       FontMetrics metrics = getFontMetrics(editor).metrics;
       startWidth = doCalcWidth(myText, metrics);
index 359b6d73665449f48f42c8dca1e1054733118788..0b641a7756dcc38351f298a1c21303fe99764d09 100644 (file)
@@ -54,96 +54,97 @@ class MoverWrapper {
     assert myInfo.toMove2 != null;
     myMover.beforeMove(editor, myInfo, myIsDown);
     final Document document = editor.getDocument();
+    final Project project = file.getProject();
+    if (!myInfo.toMove.equals(myInfo.toMove2)) { // some movers (e.g. PyStatementMover) perform actual moving inside beforeMove/afterMove
+      final int start = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.startLine);
+      final int end = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.endLine);
+      String textToInsert = document.getCharsSequence().subSequence(start, end).toString();
+      if (!StringUtil.endsWithChar(textToInsert,'\n')) textToInsert += '\n';
+
+      final int start2 = document.getLineStartOffset(myInfo.toMove2.startLine);
+      final int end2 = StatementUpDownMover.getLineStartSafeOffset(document,myInfo.toMove2.endLine);
+      String textToInsert2 = document.getCharsSequence().subSequence(start2, end2).toString();
+      if (!StringUtil.endsWithChar(textToInsert2,'\n')) textToInsert2 += '\n';
+
+      TextRange range = new TextRange(start, end);
+      TextRange range2 = new TextRange(start2, end2);
+      if (range.intersectsStrict(range2) && !range.equals(range2)) {
+        LOGGER.error("Wrong move ranges requested by " + myMover,
+                     new Attachment("ranges.txt",
+                                    start + ":" + end + "(" + textToInsert + ")\n" + start2 + ":" + end2 + "(" + textToInsert2 + ")"));
+        return;
+      }
 
-    final int start = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.startLine);
-    final int end = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.endLine);
-    String textToInsert = document.getCharsSequence().subSequence(start, end).toString();
-    if (!StringUtil.endsWithChar(textToInsert,'\n')) textToInsert += '\n';
-
-    final int start2 = document.getLineStartOffset(myInfo.toMove2.startLine);
-    final int end2 = StatementUpDownMover.getLineStartSafeOffset(document,myInfo.toMove2.endLine);
-    String textToInsert2 = document.getCharsSequence().subSequence(start2, end2).toString();
-    if (!StringUtil.endsWithChar(textToInsert2,'\n')) textToInsert2 += '\n';
-
-    TextRange range = new TextRange(start, end);
-    TextRange range2 = new TextRange(start2, end2);
-    if (range.intersectsStrict(range2) && !range.equals(range2)) {
-      LOGGER.error("Wrong move ranges requested by " + myMover,
-                   new Attachment("ranges.txt",
-                                  start + ":" + end + "(" + textToInsert + ")\n" + start2 + ":" + end2 + "(" + textToInsert2 + ")"));
-      return;
-    }
-    
-    myInfo.range1 = document.createRangeMarker(start, end);
-    myInfo.range2 = document.createRangeMarker(start2, end2);
-    if (myInfo.range1.getStartOffset() < myInfo.range2.getStartOffset()) {
-      myInfo.range1.setGreedyToLeft(true);
-      myInfo.range1.setGreedyToRight(false);
-      myInfo.range2.setGreedyToLeft(true);
-      myInfo.range2.setGreedyToRight(true);
-    }
-    else {
-      myInfo.range1.setGreedyToLeft(true);
-      myInfo.range1.setGreedyToRight(true);
-      myInfo.range2.setGreedyToLeft(true);
-      myInfo.range2.setGreedyToRight(false);
-    }
+      myInfo.range1 = document.createRangeMarker(start, end);
+      myInfo.range2 = document.createRangeMarker(start2, end2);
+      if (myInfo.range1.getStartOffset() < myInfo.range2.getStartOffset()) {
+        myInfo.range1.setGreedyToLeft(true);
+        myInfo.range1.setGreedyToRight(false);
+        myInfo.range2.setGreedyToLeft(true);
+        myInfo.range2.setGreedyToRight(true);
+      }
+      else {
+        myInfo.range1.setGreedyToLeft(true);
+        myInfo.range1.setGreedyToRight(true);
+        myInfo.range2.setGreedyToLeft(true);
+        myInfo.range2.setGreedyToRight(false);
+      }
 
-    final CaretModel caretModel = editor.getCaretModel();
-    final int caretRelativePos = caretModel.getOffset() - start;
-    final SelectionModel selectionModel = editor.getSelectionModel();
-    final int selectionStart = selectionModel.getSelectionStart();
-    final int selectionEnd = selectionModel.getSelectionEnd();
-    final boolean hasSelection = selectionModel.hasSelection();
-
-    // to prevent flicker
-    caretModel.moveToOffset(0);
-
-    // There is a possible case that the user performs, say, method move. It's also possible that one (or both) of moved methods
-    // are folded. We want to preserve their states then. The problem is that folding processing is based on PSI element pointers
-    // and the pointers behave as following during move up/down:
-    //     method1() {}
-    //     method2() {}
-    // Pointer for the fold region from method1 points to 'method2()' now and vice versa (check range markers processing on
-    // document change for further information). I.e. information about fold regions statuses holds the data swapped for
-    // 'method1' and 'method2'. Hence, we want to apply correct 'collapsed' status.
-    final FoldRegion topRegion = findTopLevelRegionInRange(editor, myInfo.range1);
-    final FoldRegion bottomRegion = findTopLevelRegionInRange(editor, myInfo.range2);
-
-    document.insertString(myInfo.range1.getStartOffset(), textToInsert2);
-    document.deleteString(myInfo.range1.getStartOffset()+textToInsert2.length(), myInfo.range1.getEndOffset());
-
-    document.insertString(myInfo.range2.getStartOffset(), textToInsert);
-    int s = myInfo.range2.getStartOffset() + textToInsert.length();
-    int e = myInfo.range2.getEndOffset();
-    if (e > s) {
-      document.deleteString(s, e);
-    }
+      final CaretModel caretModel = editor.getCaretModel();
+      final int caretRelativePos = caretModel.getOffset() - start;
+      final SelectionModel selectionModel = editor.getSelectionModel();
+      final int selectionStart = selectionModel.getSelectionStart();
+      final int selectionEnd = selectionModel.getSelectionEnd();
+      final boolean hasSelection = selectionModel.hasSelection();
+
+      // to prevent flicker
+      caretModel.moveToOffset(0);
+
+      // There is a possible case that the user performs, say, method move. It's also possible that one (or both) of moved methods
+      // are folded. We want to preserve their states then. The problem is that folding processing is based on PSI element pointers
+      // and the pointers behave as following during move up/down:
+      //     method1() {}
+      //     method2() {}
+      // Pointer for the fold region from method1 points to 'method2()' now and vice versa (check range markers processing on
+      // document change for further information). I.e. information about fold regions statuses holds the data swapped for
+      // 'method1' and 'method2'. Hence, we want to apply correct 'collapsed' status.
+      final FoldRegion topRegion = findTopLevelRegionInRange(editor, myInfo.range1);
+      final FoldRegion bottomRegion = findTopLevelRegionInRange(editor, myInfo.range2);
+
+      document.insertString(myInfo.range1.getStartOffset(), textToInsert2);
+      document.deleteString(myInfo.range1.getStartOffset()+textToInsert2.length(), myInfo.range1.getEndOffset());
+
+      document.insertString(myInfo.range2.getStartOffset(), textToInsert);
+      int s = myInfo.range2.getStartOffset() + textToInsert.length();
+      int e = myInfo.range2.getEndOffset();
+      if (e > s) {
+        document.deleteString(s, e);
+      }
 
-    final Project project = file.getProject();
-    PsiDocumentManager.getInstance(project).commitAllDocuments();
-
-    // Swap fold regions status if necessary.
-    if (topRegion != null && bottomRegion != null) {
-      CodeFoldingManager.getInstance(project).updateFoldRegions(editor);
-      editor.getFoldingModel().runBatchFoldingOperation(() -> {
-        FoldRegion newTopRegion = findTopLevelRegionInRange(editor, myInfo.range1);
-        if (newTopRegion != null) {
-          newTopRegion.setExpanded(bottomRegion.isExpanded());
-        }
-
-        FoldRegion newBottomRegion = findTopLevelRegionInRange(editor, myInfo.range2);
-        if (newBottomRegion != null) {
-          newBottomRegion.setExpanded(topRegion.isExpanded());
-        }
-      });
-    }
+      PsiDocumentManager.getInstance(project).commitAllDocuments();
+
+      // Swap fold regions status if necessary.
+      if (topRegion != null && bottomRegion != null) {
+        CodeFoldingManager.getInstance(project).updateFoldRegions(editor);
+        editor.getFoldingModel().runBatchFoldingOperation(() -> {
+          FoldRegion newTopRegion = findTopLevelRegionInRange(editor, myInfo.range1);
+          if (newTopRegion != null) {
+            newTopRegion.setExpanded(bottomRegion.isExpanded());
+          }
+
+          FoldRegion newBottomRegion = findTopLevelRegionInRange(editor, myInfo.range2);
+          if (newBottomRegion != null) {
+            newBottomRegion.setExpanded(topRegion.isExpanded());
+          }
+        });
+      }
 
-    if (hasSelection) {
-      restoreSelection(editor, selectionStart, selectionEnd, start, myInfo.range2.getStartOffset());
-    }
+      if (hasSelection) {
+        restoreSelection(editor, selectionStart, selectionEnd, start, end, myInfo.range2.getStartOffset());
+      }
 
-    caretModel.moveToOffset(myInfo.range2.getStartOffset() + caretRelativePos);
+      caretModel.moveToOffset(myInfo.range2.getStartOffset() + caretRelativePos);
+    }
     myMover.afterMove(editor, file, myInfo, myIsDown);
     PsiDocumentManager.getInstance(project).commitDocument(document);
     if (myInfo.indentTarget) {
@@ -215,10 +216,12 @@ class MoverWrapper {
     return text.trim().length() != 0;
   }
 
-  private static void restoreSelection(final Editor editor, final int selectionStart, final int selectionEnd, final int moveOffset, int insOffset) {
-    final int selectionRelativeOffset = selectionStart - moveOffset;
-    int newSelectionStart = insOffset + selectionRelativeOffset;
-    int newSelectionEnd = newSelectionStart + selectionEnd - selectionStart;
+  private static void restoreSelection(Editor editor,
+                                       int selectionStart, int selectionEnd, int moveStartOffset, int moveEndOffset, int insOffset) {
+    int selectionRelativeStartOffset = Math.max(0, selectionStart - moveStartOffset);
+    int selectionRelativeEndOffset = Math.min(moveEndOffset - moveStartOffset, selectionEnd - moveStartOffset);
+    int newSelectionStart = insOffset + selectionRelativeStartOffset;
+    int newSelectionEnd = insOffset + selectionRelativeEndOffset;
     EditorUtil.setSelectionExpandingFoldedRegionsIfNeeded(editor, newSelectionStart, newSelectionEnd);
   }
 }
index c2cb9fc2987436005aff1f52e71d4da3a1985f03..de1b87b9e592c9feb02f6648969a9a8bc166bcbe 100644 (file)
@@ -19,6 +19,7 @@ package com.intellij.codeInsight.navigation;
 import com.intellij.codeInsight.CodeInsightBundle;
 import com.intellij.codeInsight.TargetElementUtil;
 import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ReadAction;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.progress.ProgressManager;
 import com.intellij.openapi.project.DumbService;
@@ -68,7 +69,7 @@ public class ImplementationSearcher {
     if (elements.length > 0) {
       if (!includeSelfAlways) return filterElements(element, elements, offset);
       final PsiElement[] all;
-      if (element.getTextRange() != null) {
+      if (ReadAction.compute(() -> element.getTextRange()) != null) {
         all = new PsiElement[elements.length + 1];
         all[0] = element;
         System.arraycopy(elements, 0, all, 1, elements.length);
index 65403b76b9a5bf7247fbe874f44fd97509effee6..31933bc613f8fed653ceadcb4f5a01b09a0f2950 100644 (file)
@@ -19,17 +19,13 @@ package com.intellij.ide.actions;
 import com.intellij.find.FindManager;
 import com.intellij.find.FindUtil;
 import com.intellij.ide.IdeBundle;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
-import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.actionSystem.*;
 import com.intellij.openapi.command.CommandProcessor;
 import com.intellij.openapi.fileEditor.FileEditor;
 import com.intellij.openapi.fileEditor.TextEditor;
 import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
-import com.intellij.openapi.project.Project;
 import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
 import com.intellij.psi.PsiDocumentManager;
 
 public class SearchAgainAction extends AnAction implements DumbAware {
index 978471cef90f05be896dd5e476c71800ce208d83..3676234bdccf06dc283db711b08aa7cb8addf3c6 100644 (file)
@@ -19,16 +19,12 @@ package com.intellij.ide.actions;
 import com.intellij.find.FindManager;
 import com.intellij.find.FindUtil;
 import com.intellij.ide.IdeBundle;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
-import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.actionSystem.*;
 import com.intellij.openapi.command.CommandProcessor;
 import com.intellij.openapi.fileEditor.FileEditor;
 import com.intellij.openapi.fileEditor.TextEditor;
-import com.intellij.openapi.project.Project;
 import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
 import com.intellij.psi.PsiDocumentManager;
 
 public class SearchBackAction extends AnAction implements DumbAware {
diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkAsContentRootAction.kt b/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkAsContentRootAction.kt
new file mode 100644 (file)
index 0000000..2228bb3
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.ide.projectView.actions
+
+import com.intellij.ide.projectView.impl.ProjectRootsUtil
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.actionSystem.CommonDataKeys
+import com.intellij.openapi.project.DumbAwareAction
+import com.intellij.openapi.roots.ModuleRootManager
+import com.intellij.openapi.roots.ProjectRootManager
+
+/**
+ * @author nik
+ */
+class MarkAsContentRootAction : DumbAwareAction() {
+  override fun update(e: AnActionEvent) {
+    val files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY)
+    val module = MarkRootActionBase.getModule(e, files)
+    if (module == null || files == null) {
+      e.presentation.isEnabledAndVisible = false
+      return
+    }
+    val fileIndex = ProjectRootManager.getInstance(module.project).fileIndex
+    e.presentation.isEnabledAndVisible = files.all {
+      it.isDirectory && fileIndex.isExcluded(it) && ProjectRootsUtil.findExcludeFolder(module, it) == null
+    }
+  }
+
+  override fun actionPerformed(e: AnActionEvent) {
+    val files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return
+    val module = MarkRootActionBase.getModule(e, files) ?: return
+    val model = ModuleRootManager.getInstance(module).modifiableModel
+    files.forEach {
+      model.addContentEntry(it)
+    }
+    MarkRootActionBase.commitModel(module, model)
+  }
+}
index 7fbb9c3b9eca8362711377a62f3eb26da38cd411..66212f72d03c55c58dfc6d1d8fe9b7d8369b810a 100644 (file)
@@ -15,6 +15,7 @@
  */
 package com.intellij.ide.projectView.actions;
 
+import com.intellij.icons.AllIcons;
 import com.intellij.openapi.actionSystem.AnActionEvent;
 import com.intellij.openapi.actionSystem.CommonDataKeys;
 import com.intellij.openapi.module.Module;
@@ -29,6 +30,10 @@ import org.jetbrains.annotations.NotNull;
  * @author yole
  */
 public class MarkExcludeRootAction extends MarkRootActionBase {
+  public MarkExcludeRootAction() {
+    super(null, null, AllIcons.Modules.ExcludeRoot);
+  }
+
   @Override
   public void actionPerformed(AnActionEvent e) {
     VirtualFile[] files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY);
index 4e7683e180b575962e0256841afaa32e138e4424..0c5d26fdaf1568414c2cc3576523ce0b1bc73dde 100644 (file)
@@ -77,6 +77,10 @@ public abstract class MarkRootActionBase extends DumbAwareAction {
         modifyRoots(file, entry);
       }
     }
+    commitModel(module, model);
+  }
+
+  static void commitModel(@NotNull Module module, ModifiableRootModel model) {
     DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND,
                                             () -> ApplicationManager.getApplication().runWriteAction(() -> {
                                               model.commit();
@@ -148,7 +152,7 @@ public abstract class MarkRootActionBase extends DumbAwareAction {
   }
 
   @Nullable
-  private static Module getModule(@NotNull AnActionEvent e, @Nullable VirtualFile[] files) {
+  static Module getModule(@NotNull AnActionEvent e, @Nullable VirtualFile[] files) {
     if (files == null) return null;
     Module module = e.getData(LangDataKeys.MODULE);
     if (module == null) {
index 127d4a64a2ffaee858e51f90d94c0828ff575569..d2f584560bb7cd714ab3774dc4ac88f1afc2c5d6 100644 (file)
@@ -42,6 +42,7 @@ import com.intellij.psi.*;
 import com.intellij.psi.search.PsiElementProcessor;
 import com.intellij.psi.util.PsiUtilCore;
 import com.intellij.util.FontUtil;
+import com.intellij.util.containers.ContainerUtil;
 import gnu.trove.THashSet;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -212,6 +213,19 @@ public class ProjectViewDirectoryHelper {
     return topLevelContentRoots;
   }
 
+  public List<VirtualFile> getTopLevelModuleRoots(Module module, ViewSettings settings) {
+    return ContainerUtil.filter(ModuleRootManager.getInstance(module).getContentRoots(), root -> {
+      if (!shouldBeShown(root, settings)) return false;
+      VirtualFile parent = root.getParent();
+      if (parent == null) return true;
+      DirectoryInfo info = myIndex.getInfoForFile(parent);
+      if (!module.equals(info.getModule())) return true;
+      //show inner content root separately only if it won't be shown under outer content root
+      return info.isExcluded() && !shouldShowExcludedFiles(settings);
+    });
+  }
+
+
   private static boolean isFileInContent(ProjectFileIndex index, VirtualFile file) {
     while (file != null) {
       if (index.isInContent(file)) {
@@ -260,12 +274,11 @@ public class ProjectViewDirectoryHelper {
 
   private boolean shouldBeShown(VirtualFile dir, ViewSettings settings) {
     DirectoryInfo directoryInfo = myIndex.getInfoForFile(dir);
-    if (directoryInfo.isInProject()) return true;
+    return directoryInfo.isInProject() || shouldShowExcludedFiles(settings) && directoryInfo.isExcluded();
+  }
 
-    if (!Registry.is("ide.hide.excluded.files") && settings instanceof ProjectViewSettings && ((ProjectViewSettings)settings).isShowExcludedFiles()) {
-      return directoryInfo.isExcluded();
-    }
-    return false;
+  private static boolean shouldShowExcludedFiles(ViewSettings settings) {
+    return !Registry.is("ide.hide.excluded.files") && settings instanceof ProjectViewSettings && ((ProjectViewSettings)settings).isShowExcludedFiles();
   }
 
   // used only for non-flatten packages mode
index 1b51e33c03537805b062cb079210e4c81213a4e9..9da0e81d4765dc91c77eb9ba085bffd41f264f0d 100644 (file)
@@ -46,15 +46,11 @@ public class ProjectViewModuleNode extends AbstractModuleNode {
     if (module == null || module.isDisposed()) {  // module has been disposed
       return Collections.emptyList();
     }
-    ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
-    ModuleFileIndex moduleFileIndex = rootManager.getFileIndex();
 
-    final VirtualFile[] contentRoots = rootManager.getContentRoots();
-    final List<AbstractTreeNode> children = new ArrayList<>(contentRoots.length + 1);
+    final List<VirtualFile> contentRoots = ProjectViewDirectoryHelper.getInstance(myProject).getTopLevelModuleRoots(module, getSettings());
+    final List<AbstractTreeNode> children = new ArrayList<>(contentRoots.size());
     final PsiManager psiManager = PsiManager.getInstance(module.getProject());
     for (final VirtualFile contentRoot : contentRoots) {
-      if (!moduleFileIndex.isInContent(contentRoot)) continue;
-
       if (contentRoot.isDirectory()) {
         PsiDirectory directory = psiManager.findDirectory(contentRoot);
         if (directory != null) {
@@ -68,12 +64,6 @@ public class ProjectViewModuleNode extends AbstractModuleNode {
         }
       }
     }
-
-    /*
-    if (getSettings().isShowLibraryContents()) {
-      children.add(new LibraryGroupNode(getProject(), new LibraryGroupElement(getValue()), getSettings()));
-    }
-    */
     return children;
   }
 
index 2e41e8db07e16032571014d0220b6de2f082ebf2..f89abd9b0b330856e3e80397fdb07595f943d254 100644 (file)
@@ -22,7 +22,6 @@ import com.intellij.ide.util.treeView.AbstractTreeNode;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.module.ModuleUtil;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.ModuleRootManager;
 import com.intellij.openapi.roots.ProjectFileIndex;
 import com.intellij.openapi.util.Comparing;
 import com.intellij.openapi.util.io.FileUtil;
@@ -125,9 +124,9 @@ public class ProjectViewProjectNode extends AbstractProjectNode {
   @Override
   protected AbstractTreeNode createModuleGroup(final Module module)
     throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
-    final VirtualFile[] roots = ModuleRootManager.getInstance(module).getContentRoots();
-    if (roots.length == 1) {
-      final PsiDirectory psi = PsiManager.getInstance(myProject).findDirectory(roots[0]);
+    List<VirtualFile> roots = ProjectViewDirectoryHelper.getInstance(myProject).getTopLevelModuleRoots(module, getSettings());
+    if (roots.size() == 1) {
+      final PsiDirectory psi = PsiManager.getInstance(myProject).findDirectory(roots.get(0));
       if (psi != null) {
         return new PsiDirectoryNode(myProject, psi, getSettings());
       }
index 4eae11fa4f8bcff12f08253c2d5dbeb10c86a2a2..c789c913d2c16fb890a331d108a4d913d774638c 100644 (file)
@@ -65,7 +65,7 @@ public class CopyFilesOrDirectoriesDialog extends DialogWrapper {
   private static final String COPY_OPEN_IN_EDITOR = "Copy.OpenInEditor";
   private static final String RECENT_KEYS = "CopyFile.RECENT_KEYS";
 
-  public static String shortenPath(VirtualFile file) {
+  public static String shortenPath(@NotNull VirtualFile file) {
     return StringUtil.shortenPathWithEllipsis(file.getPresentableUrl(), MAX_PATH_LENGTH);
   }
 
@@ -107,6 +107,12 @@ public class CopyFilesOrDirectoriesDialog extends DialogWrapper {
     setTitle(RefactoringBundle.message(doClone ? "copy.files.clone.title" : "copy.files.copy.title"));
     init();
 
+    for (int i = 0; i < elements.length; i++) {
+      if (elements[i] instanceof PsiFile) {
+        elements[i] = ((PsiFile)elements[i]).getOriginalFile();
+      }
+    }
+
     if (elements.length == 1) {
       String text;
       if (elements[0] instanceof PsiFile) {
index 773d6859835de6cd30950de5e8cd703366dda1b0..d0c686fcede91d9099f687ab7ee326fbca251f41 100644 (file)
@@ -15,6 +15,8 @@
  */
 package com.intellij.refactoring.rename.inplace;
 
+import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
+import com.intellij.codeInsight.template.impl.TemplateState;
 import com.intellij.lang.Language;
 import com.intellij.lang.LanguageExtension;
 import com.intellij.openapi.application.ApplicationManager;
@@ -46,7 +48,6 @@ import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory;
 import com.intellij.refactoring.util.CommonRefactoringUtil;
 import com.intellij.refactoring.util.TextOccurrencesUtil;
 import com.intellij.usageView.UsageInfo;
-import com.intellij.util.PairProcessor;
 import com.intellij.util.containers.MultiMap;
 import org.jetbrains.annotations.NotNull;
 
@@ -158,6 +159,17 @@ public class VariableInplaceRenamer extends InplaceRefactoring {
   @Override
   protected void restoreSelection() {
     if (mySelectedRange != null) {
+      TemplateState state = TemplateManagerImpl.getTemplateState(InjectedLanguageUtil.getTopLevelEditor(myEditor));
+      if (state != null) {
+        for (int i = 0; i < state.getSegmentsCount(); i++) {
+          final TextRange segmentRange = state.getSegmentRange(i);
+          TextRange intersection = segmentRange.intersection(mySelectedRange);
+          if (intersection != null) {
+            myEditor.getSelectionModel().setSelection(intersection.getStartOffset(), intersection.getEndOffset());
+            return;
+          }
+        }
+      }
       myEditor.getSelectionModel().setSelection(mySelectedRange.getStartOffset(), mySelectedRange.getEndOffset());
     }
     else if (!shouldSelectAll()) {
similarity index 95%
rename from java/java-impl/src/com/intellij/reporting/ReportMissingOrExcessiveInlineHint.kt
rename to platform/lang-impl/src/com/intellij/reporting/ReportExcessiveInlineHint.kt
index 3e06f1ae1231eac23036db4566fd5ba636a148da..d18d9dc482302c70d9db9c12b04644098044f10a 100644 (file)
@@ -31,13 +31,13 @@ import com.intellij.openapi.project.Project
 import com.intellij.openapi.util.TextRange
 import java.io.File
 
-class ReportMissingOrExcessiveInlineHint : AnAction() {
+class ReportExcessiveInlineHint : AnAction() {
   
-  private val text = "Report Missing or Excessive Inline Hint"
+  private val text = "Report Excessive Inline Hint"
   private val description = "Text line at caret will be anonymously reported to our servers"
   
   companion object {
-    private val LOG = Logger.getInstance(ReportMissingOrExcessiveInlineHint::class.java)
+    private val LOG = Logger.getInstance(ReportExcessiveInlineHint::class.java)
   }
   
   init {
index 1058f67f4f7f45a22e549d0c075c2d807814843f..9af147f188b29f233ffc11e1f660e1507974afd0 100644 (file)
@@ -37,20 +37,19 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
 import com.intellij.openapi.ui.popup.ListPopup;
 import com.intellij.openapi.ui.popup.PopupStep;
 import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
-import com.intellij.openapi.util.AtomicNotNullLazyValue;
-import com.intellij.openapi.util.NotNullLazyValue;
-import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.*;
 import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vfs.JarFileSystem;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.vfs.VirtualFileSystem;
 import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem;
 import com.intellij.ui.awt.RelativePoint;
 import com.intellij.util.Consumer;
+import com.intellij.util.SystemProperties;
 import com.intellij.util.ui.EmptyIcon;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.ide.PooledThreadExecutor;
 
 import javax.swing.*;
 import javax.swing.event.HyperlinkEvent;
@@ -62,8 +61,9 @@ import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import static com.intellij.openapi.util.text.StringUtil.defaultIfEmpty;
 
 public class ShowFilePathAction extends AnAction {
   private static final Logger LOG = Logger.getInstance("#com.intellij.ide.actions.ShowFilePathAction");
@@ -77,22 +77,13 @@ public class ShowFilePathAction extends AnAction {
     }
   };
 
-  private static NotNullLazyValue<Boolean> canUseNautilus = new AtomicNotNullLazyValue<Boolean>() {
-    @NotNull
+  private static NullableLazyValue<String> fileManagerApp = new AtomicNullableLazyValue<String>() {
     @Override
-    protected Boolean compute() {
-      if (!SystemInfo.isUnix || !SystemInfo.hasXdgMime() || !new File("/usr/bin/nautilus").canExecute()) {
-        return false;
-      }
-
-      String appName = ExecUtil.execAndReadLine(new GeneralCommandLine("xdg-mime", "query", "default", "inode/directory"));
-      if (appName == null || !appName.matches("nautilus.*\\.desktop")) return false;
-
-      String version = ExecUtil.execAndReadLine(new GeneralCommandLine("nautilus", "--version"));
-      if (version == null) return false;
-
-      Matcher m = Pattern.compile("GNOME nautilus ([0-9.]+)").matcher(version);
-      return m.find() && StringUtil.compareVersionNumbers(m.group(1), "3") >= 0;
+    protected String compute() {
+      return readDesktopEntryKey("Exec")
+        .map(line -> line.split(" ")[0])
+        .filter(exec -> exec.endsWith("nautilus") || exec.endsWith("pantheon-files"))
+        .orElse(null);
     }
   };
 
@@ -102,41 +93,42 @@ public class ShowFilePathAction extends AnAction {
     protected String compute() {
       if (SystemInfo.isMac) return "Finder";
       if (SystemInfo.isWindows) return "Explorer";
-      if (SystemInfo.isUnix && SystemInfo.hasXdgMime()) {
-        String name = getUnixFileManagerName();
-        if (name != null) return name;
-      }
-      return "File Manager";
+      return readDesktopEntryKey("Name").orElse("File Manager");
     }
   };
 
-  @Nullable
-  private static String getUnixFileManagerName() {
-    String appName = ExecUtil.execAndReadLine(new GeneralCommandLine("xdg-mime", "query", "default", "inode/directory"));
-    if (appName == null || !appName.matches(".+\\.desktop")) return null;
+  private static Optional<String> readDesktopEntryKey(String key) {
+    if (SystemInfo.hasXdgMime()) {
+      String appName = ExecUtil.execAndReadLine(new GeneralCommandLine("xdg-mime", "query", "default", "inode/directory"));
+      if (appName != null && appName.endsWith(".desktop")) {
+        return Stream.of(getXdgDataDirectories().split(":"))
+          .map(dir -> new File(dir, "applications/" + appName))
+          .filter(File::exists)
+          .findFirst()
+          .map(file -> readDesktopEntryKey(file, key + '='));
+      }
+    }
 
-    String dirs = System.getenv("XDG_DATA_DIRS");
-    if (dirs == null) return null;
+    return Optional.empty();
+  }
 
-    try {
-      for (String dir : dirs.split(File.pathSeparator)) {
-        File appFile = new File(dir, "applications/" + appName);
-        if (appFile.exists()) {
-          try (BufferedReader reader = new BufferedReader(new FileReader(appFile))) {
-            Optional<String> name = reader.lines().filter(l -> l.startsWith("Name=")).map(l -> l.substring(5)).findFirst();
-            if (name.isPresent()) return name.get();
-          }
-        }
-      }
+  private static String getXdgDataDirectories() {
+    String dataHome = System.getenv("XDG_DATA_HOME");
+    String dataDirs = System.getenv("XDG_DATA_DIRS");
+    return defaultIfEmpty(dataHome, SystemProperties.getUserHome() + "/.local/share") + ':' + defaultIfEmpty(dataDirs, "/usr/local/share:/usr/share");
+  }
+
+  private static String readDesktopEntryKey(File file, String key) {
+    try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
+      return reader.lines().filter(l -> l.startsWith(key)).map(l -> l.substring(key.length())).findFirst().orElse(null);
     }
     catch (IOException | UncheckedIOException e) {
-      LOG.info("Cannot read desktop file", e);
+      LOG.info("Cannot read: " + file, e);
+      return null;
     }
-
-    return null;
   }
 
-  @Override
+@Override
   public void update(@NotNull AnActionEvent e) {
     boolean visible = !SystemInfo.isMac && isSupported();
     e.getPresentation().setVisible(visible);
@@ -223,8 +215,7 @@ public class ShowFilePathAction extends AnAction {
   }
 
   public static boolean isSupported() {
-    return SystemInfo.isWindows || SystemInfo.isMac ||
-           SystemInfo.hasXdgOpen() || canUseNautilus.getValue() ||
+    return SystemInfo.isWindows || SystemInfo.isMac || SystemInfo.hasXdgOpen() ||
            Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN);
   }
 
@@ -292,9 +283,16 @@ public class ShowFilePathAction extends AnAction {
       GeneralCommandLine cmd = toSelect != null ? new GeneralCommandLine("open", "-R", toSelect) : new GeneralCommandLine("open", dir);
       ExecUtil.execAndGetOutput(cmd).checkSuccess(LOG);
     }
-    else if (canUseNautilus.getValue()) {
-      GeneralCommandLine cmd = new GeneralCommandLine("nautilus", toSelect != null ? toSelect : dir);
-      ExecUtil.execAndGetOutput(cmd).checkSuccess(LOG);
+    else if (fileManagerApp.getValue() != null) {
+      PooledThreadExecutor.INSTANCE.submit(() -> {
+        try {
+          GeneralCommandLine cmd = new GeneralCommandLine(fileManagerApp.getValue(), toSelect != null ? toSelect : dir);
+          ExecUtil.execAndGetOutput(cmd).checkSuccess(LOG);
+        }
+        catch (Exception e) {
+          LOG.warn(e);
+        }
+      });
     }
     else if (SystemInfo.hasXdgOpen()) {
       GeneralCommandLine cmd = new GeneralCommandLine("/usr/bin/xdg-open", dir);
index 785be9e58a74b33732caa970b1370196168d167d..fbd0a59e035827cfaf4ebd733abbf55173087d40 100644 (file)
@@ -82,7 +82,7 @@ public class CustomizePluginsStepPanel extends AbstractCustomizeWizardStep imple
       gbc.fill = GridBagConstraints.BOTH;
       gbc.gridwidth = GridBagConstraints.REMAINDER;
       gbc.weightx = 1;
-      JLabel titleLabel = new JLabel("<html><body><h2 style=\"text-align:left;\">" + group + "</h2></body></html>", SwingConstants.CENTER) {
+      JLabel titleLabel = new JLabel("<html><body><h2 style=\"text-align:center;\">" + group + "</h2></body></html>", SwingConstants.CENTER) {
         @Override
         public boolean isEnabled() {
           return isGroupEnabled(group);
index 405207bf8871988eb8453bf871d2a85109a03207..78986c74ffe863259bfff48555aaf34271c8883c 100644 (file)
@@ -346,13 +346,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Disposab
       reportActionError(pluginId, "keymap \"" + keymapName + "\" not found");
       return;
     }
-
-    final String removeOption = element.getAttributeValue(REMOVE_SHORTCUT_ATTR_NAME);
-    if (Boolean.valueOf(removeOption)) {
-      keymap.removeShortcut(actionId, shortcut);
-    } else {
-      keymap.addShortcut(actionId, shortcut);
-    }
+    processRemoveAndReplace(element, actionId, keymap, shortcut);
   }
 
   private static void assertActionIsGroupOrStub(final AnAction action) {
@@ -911,16 +905,20 @@ public final class ActionManagerImpl extends ActionManagerEx implements Disposab
       reportActionWarning(pluginId, "keymap \"" + keymapName + "\" not found");
       return;
     }
-    final String removeOption = element.getAttributeValue(REMOVE_SHORTCUT_ATTR_NAME);
     final KeyboardShortcut shortcut = new KeyboardShortcut(firstKeyStroke, secondKeyStroke);
-    final String replaceOption = element.getAttributeValue(REPLACE_SHORTCUT_ATTR_NAME);
-    if (Boolean.valueOf(removeOption)) {
+    processRemoveAndReplace(element, actionId, keymap, shortcut);
+  }
+
+  private static void processRemoveAndReplace(Element element, String actionId, Keymap keymap, Shortcut shortcut) {
+    boolean remove = Boolean.parseBoolean(element.getAttributeValue(REMOVE_SHORTCUT_ATTR_NAME));
+    boolean replace = Boolean.parseBoolean(element.getAttributeValue(REPLACE_SHORTCUT_ATTR_NAME));
+    if (remove) {
       keymap.removeShortcut(actionId, shortcut);
     }
-    if (Boolean.valueOf(replaceOption)) {
+    if (replace) {
       keymap.removeAllActionShortcuts(actionId);
     }
-    if (!Boolean.valueOf(removeOption)) {
+    if (!remove) {
       keymap.addShortcut(actionId, shortcut);
     }
   }
index 8268b772f519c92d5a3811dc4b5e58f3e5115711..830e96330cf9579d124e107821a9771a40e515e7 100644 (file)
@@ -23,6 +23,7 @@ import com.intellij.openapi.actionSystem.DataProvider;
 import com.intellij.openapi.application.ex.ApplicationInfoEx;
 import com.intellij.openapi.components.ServiceManager;
 import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.colors.EditorColors;
 import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
 import com.intellij.openapi.editor.impl.EditorComponentImpl;
 import com.intellij.openapi.fileEditor.impl.EditorEmptyTextPainter;
@@ -178,25 +179,34 @@ public class IdeBackgroundUtil {
     }
   }
 
+  static final RenderingHints.Key ADJUST_ALPHA = new RenderingHints.Key(1) {
+    @Override
+    public boolean isCompatibleValue(Object val) {
+      return val instanceof Boolean;
+    }
+  };
+
   private static class MyGraphics extends Graphics2DDelegate {
     final PaintersHelper helper;
     final int[] offsets;
-    
+    Color preserved;
+
     static Graphics2D wrap(Graphics g, PaintersHelper helper, JComponent component) {
-      return new MyGraphics(g instanceof MyGraphics ? ((MyGraphics)g).getDelegate() : g,
-                            helper, helper.computeOffsets(g, component));
+      MyGraphics gg = g instanceof MyGraphics ? (MyGraphics)g : null;
+      return new MyGraphics(gg != null ? gg.myDelegate : g, helper, helper.computeOffsets(g, component), gg != null ? gg.preserved : null);
     }
 
-    MyGraphics(Graphics g, PaintersHelper helper, int[] offsets) {
+    MyGraphics(Graphics g, PaintersHelper helper, int[] offsets, Color preserved) {
       super((Graphics2D)g);
       this.helper = helper;
       this.offsets = offsets;
+      this.preserved = preserved;
     }
 
     @NotNull
     @Override
     public Graphics create() {
-      return new MyGraphics(getDelegate().create(), helper, offsets);
+      return new MyGraphics(getDelegate().create(), helper, offsets, preserved);
     }
 
     @Override
@@ -246,13 +256,20 @@ public class IdeBackgroundUtil {
         if (!(reason instanceof BufferedImage)) return;
         if (((BufferedImage)reason).getColorModel().hasAlpha()) return;
       }
+      boolean preserve = reason instanceof Color && reason.equals(preserved);
+      if (preserve) {
+        myDelegate.setRenderingHint(ADJUST_ALPHA, Boolean.TRUE);
+      }
 
       Shape s = getClip();
       Rectangle newClip = s == null ? new Rectangle(x, y, width, height) :
                           SwingUtilities.computeIntersection(x, y, width, height, s.getBounds());
       setClip(newClip);
-      helper.runAllPainters(getDelegate(), offsets);
+      helper.runAllPainters(myDelegate, offsets);
       setClip(s);
+      if (preserve) {
+        myDelegate.setRenderingHint(ADJUST_ALPHA, Boolean.FALSE);
+      }
     }
   }
 
@@ -260,13 +277,30 @@ public class IdeBackgroundUtil {
     @Override
     public Graphics2D fun(JComponent c, Graphics2D g) {
       String type = getComponentType(c);
+      if (type == null) return g;
+      if ("frame".equals(type)) return withFrameBackground(g, c);
       if ("editor".equals(type)) {
+        //noinspection CastConflictsWithInstanceof
         Editor editor = c instanceof EditorComponentImpl ? ((EditorComponentImpl)c).getEditor() :
                         c instanceof EditorGutterComponentEx ? CommonDataKeys.EDITOR.getData((DataProvider)c) : null;
-        if (Boolean.TRUE.equals(EditorTextField.SUPPLEMENTARY_KEY.get(editor))) return g;
+        if (editor != null) {
+          if (!(g instanceof MyGraphics) && Boolean.TRUE.equals(EditorTextField.SUPPLEMENTARY_KEY.get(editor))) return g;
+          Graphics2D gg = withEditorBackground(g, c);
+          if (gg instanceof MyGraphics) {
+            ((MyGraphics)gg).preserved = editor.getColorsScheme().getColor(EditorColors.SELECTION_BACKGROUND_COLOR);
+          }
+          return gg;
+        }
       }
-      if ("frame".equals(type)) return withFrameBackground(g, c);
-      return type != null ? withEditorBackground(g, c) : g;
+      Graphics2D gg = withEditorBackground(g, c);
+      if (gg instanceof MyGraphics) {
+        Component view = c instanceof JViewport ? ((JViewport)c).getView() : c;
+        ((MyGraphics)gg).preserved = view instanceof JTree ? UIUtil.getTreeSelectionBackground() :
+                                     view instanceof JList ? UIUtil.getListSelectionBackground() :
+                                     view instanceof JTable ? UIUtil.getTableSelectionBackground() :
+                                     null;
+      }
+      return gg;
     }
   }
 }
index ce89e12cc406e6da81f8aceabcd1b32ac1feec17..73b5340f2078bacd07972b01069055565f6981d3 100644 (file)
@@ -370,7 +370,8 @@ final class PaintersHelper implements Painter.Listener {
         return;
       }
 
-      GraphicsConfig gc = new GraphicsConfig(g).setAlpha(alpha);
+      float adjustedAlpha = Boolean.TRUE.equals(g.getRenderingHint(IdeBackgroundUtil.ADJUST_ALPHA)) ? alpha / 2 : alpha;
+      GraphicsConfig gc = new GraphicsConfig(g).setAlpha(adjustedAlpha);
       UIUtil.drawImage(g, scaled, x, y, w, h, null);
 
       gc.restore();
index 2a3d123c688a84b424b6665da977b6c885acb4f5..510e6bd8a5bb1f14471a6f4cb22d191e36342045 100644 (file)
@@ -20,31 +20,50 @@ import java.awt.*;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusEvent;
 import java.awt.event.FocusListener;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
 
-/**
- * @author Denis Fokin
- */
+import static java.awt.GridBagConstraints.CENTER;
 
 /**
+ * @author Denis Fokin
+ *
  * JComboBox<String> comboBox = new ComboBox<>(new String[] {"First", "Second", "Third"});
  * comboBox.setEditable(true);
  * comboBox.setEditor(new ComboBoxCompositeEditor(new EditorTextField(), new JLabel(AllIcons.Icon_CE)));
- * @param <ItemType>
- * @param <FocusableComponentType>
+ * @param <I>
+ * @param <F>
  */
 
-public class ComboBoxCompositeEditor<ItemType, FocusableComponentType extends JComponent> extends JComponent implements ComboBoxEditor {
+public class ComboBoxCompositeEditor<I, F extends JComponent> extends JPanel implements ComboBoxEditor {
+
+  public static <ItemType, FocusableComponentType extends JComponent> ComboBoxCompositeEditor<ItemType, FocusableComponentType> withComponents (final JComponent ... components) {
+    return new ComboBoxCompositeEditor<>(components);
+  }
+
+  private BiConsumer<I, F>  myOnSetItemHandler = null;
+  private BiFunction<I, F, I>  myOnGetItemHandler = null;
 
-  public interface EditorComponent<FocusableComponentType, ItemType> {
-    void setItem(ItemType anObject);
-    ItemType getItem();
+  public ComboBoxCompositeEditor<I, F> onSetItem (BiConsumer<I, F> onSetItemHandler) {
+    myOnSetItemHandler = onSetItemHandler;
+    return this;
+  }
+
+  public ComboBoxCompositeEditor<I, F> onGetItem (BiFunction<I, F, I> onGetItemHandler) {
+    myOnGetItemHandler = onGetItemHandler;
+    return this;
+  }
+
+  public interface EditorComponent<F, I> {
+    void setItem(I anObject);
+    I getItem();
     void selectAll();
     void addActionListener(ActionListener l);
     void removeActionListener(ActionListener l);
     JComponent getDelegate();
   }
 
-  public ComboBoxCompositeEditorStrategy getStrategy(FocusableComponentType focuasbleComponent) {
+  private ComboBoxCompositeEditorStrategy getStrategy(F focuasbleComponent) {
     ComboBoxCompositeEditorStrategy strategy = null;
     if (focuasbleComponent instanceof JTextField) {
       strategy = jTextFieldStrategy;
@@ -54,20 +73,37 @@ public class ComboBoxCompositeEditor<ItemType, FocusableComponentType extends JC
     return strategy;
   }
 
-  abstract class ComboBoxCompositeEditorStrategy<FocusableComponentType> {
+  abstract class ComboBoxCompositeEditorStrategy {
+
+    abstract void setItem(F component, I anObject);
 
-    abstract void setItem(JComponent component, ItemType anObject);
+    abstract void selectAll(F component);
 
-    abstract void selectAll(JComponent component);
+    abstract void addActionListener(F component, ActionListener l) ;
 
-    abstract void addActionListener(JComponent component, ActionListener l) ;
+    abstract void removeActionListener(F component, ActionListener l) ;
 
-    abstract void removeActionListener(JComponent component, ActionListener l) ;
+    abstract I getItem(F component, I item);
   }
 
-  private ComboBoxCompositeEditorStrategy editorTextFieldStrategy = new ComboBoxCompositeEditorStrategy<ItemType> () {
-    public void setItem(JComponent component, ItemType anObject) {
-      ((EditorTextField)component).setText((anObject == null) ? "" : anObject.toString());
+  private ComboBoxCompositeEditorStrategy editorTextFieldStrategy = new ComboBoxCompositeEditorStrategy () {
+
+    BiConsumer<I, EditorTextField> defaultOnSetHandler = (anObject, component) -> component.setText((anObject == null) ? "" : anObject.toString());
+
+    public void setItem(F component, I anObject) {
+      if (myOnSetItemHandler == null) {
+        defaultOnSetHandler.accept(anObject, (EditorTextField)component);
+      } else {
+        myOnSetItemHandler.accept(anObject, component);
+      }
+    }
+
+    public I getItem(F component, I anObject) {
+      if (myOnGetItemHandler == null) {
+        return anObject;
+      } else {
+        return myOnGetItemHandler.apply(anObject, component);
+      }
     }
 
     public void selectAll(JComponent component) {
@@ -83,9 +119,24 @@ public class ComboBoxCompositeEditor<ItemType, FocusableComponentType extends JC
     }
   };
 
-  private ComboBoxCompositeEditorStrategy jTextFieldStrategy =  new ComboBoxCompositeEditorStrategy<ItemType> (){
-    public void setItem(JComponent component, ItemType anObject) {
-      ((JTextField)component).setText((anObject ==null) ? "" : anObject.toString());
+  private ComboBoxCompositeEditorStrategy jTextFieldStrategy =  new ComboBoxCompositeEditorStrategy() {
+
+    BiConsumer<I, JTextField> defaultOnSetHandler = (anObject, component) ->  component.setText((anObject ==null) ? "" : anObject.toString());
+
+    public void setItem(F component, I anObject) {
+      if (myOnSetItemHandler == null) {
+        defaultOnSetHandler.accept(anObject, (JTextField)component);
+      } else {
+        myOnSetItemHandler.accept(anObject, component);
+      }
+    }
+
+    public I getItem(F component, I anObject) {
+      if (myOnGetItemHandler == null) {
+        return anObject;
+      } else {
+        return myOnGetItemHandler.apply(anObject, component);
+      }
     }
 
     public void selectAll(JComponent component) {
@@ -101,49 +152,59 @@ public class ComboBoxCompositeEditor<ItemType, FocusableComponentType extends JC
     }
   };
 
-  private final EditorComponent<FocusableComponentType, ItemType>[] myComponents;
-  private ItemType myItem = null;
+  private final EditorComponent<F, I>[] myComponents;
   private int focusableComponentIndex;
 
   public ComboBoxCompositeEditor(final JComponent ... components) {
     assert components.length > 0;
-    setLayout(new GridLayout(1, 0));
+    //setLayout(new GridLayout(1, 0));
+    setLayout(new GridBagLayout());
     setFocusable(false);
     myComponents = new EditorComponent[components.length];
 
+    GridBagConstraints c = new GridBagConstraints();
+
+    c.fill = GridBagConstraints.BOTH;
+    c.weightx = 1;
+    c.gridy = 0;
+    c.anchor = CENTER;
+    c.ipadx = 0;
+    c.ipady = 0;
+
     for (int i = 0; i < components.length; i ++) {
-      final int index = i;
-      add(components[i]);
+      c.gridx = i;
+      add(components[i], c);
+      c.weightx = 0;
     }
 
-    final ComboBoxCompositeEditorStrategy strategy = getStrategy((FocusableComponentType)components[focusableComponentIndex]);
+    final ComboBoxCompositeEditorStrategy strategy = getStrategy((F)components[focusableComponentIndex]);
 
-    myComponents[focusableComponentIndex] = new ComboBoxCompositeEditor.EditorComponent<FocusableComponentType, ItemType>() {
+    myComponents[focusableComponentIndex] = new ComboBoxCompositeEditor.EditorComponent<F, I>() {
 
-      ItemType myItem;
+      I myItem;
 
-      public void setItem(ItemType anObject) {
+      public void setItem(I anObject) {
         myItem = anObject;
-        strategy.setItem(components[focusableComponentIndex], anObject);
+        strategy.setItem((F)components[focusableComponentIndex], anObject);
       }
 
-      public ItemType getItem() {
-        return myItem;
+      public I getItem() {
+        return strategy.getItem((F)components[focusableComponentIndex], myItem);
       }
 
       @Override
       public void selectAll() {
-        strategy.selectAll(components[focusableComponentIndex]);
+        strategy.selectAll((F)components[focusableComponentIndex]);
       }
 
       @Override
       public void addActionListener(ActionListener l) {
-        strategy.addActionListener(components[focusableComponentIndex], l);
+        strategy.addActionListener((F)components[focusableComponentIndex], l);
       }
 
       @Override
       public void removeActionListener(ActionListener l) {
-        strategy.removeActionListener(components[focusableComponentIndex], l);
+        strategy.removeActionListener((F)components[focusableComponentIndex], l);
       }
 
       @Override
@@ -152,7 +213,6 @@ public class ComboBoxCompositeEditor<ItemType, FocusableComponentType extends JC
       }
     };
 
-
     invalidate();
 
     focusableComponentIndex = 0;
@@ -182,12 +242,12 @@ public class ComboBoxCompositeEditor<ItemType, FocusableComponentType extends JC
 
   @Override
   public void setItem(Object anObject) {
-    myComponents[focusableComponentIndex].setItem((ItemType)anObject);
+    myComponents[focusableComponentIndex].setItem((I)anObject);
   }
 
   @Override
   public Object getItem() {
-    return myItem;
+    return myComponents[focusableComponentIndex].getItem();
   }
 
   @Override
index f00ecb4f51d1500293866a3d2a41fef8d4cfe043..fcd5d571cb2e241080e30e34ae42be7823ab420a 100644 (file)
@@ -416,6 +416,8 @@ action.ShowSiblings.text=Show Siblings
 action.ShowSiblings.description=Show a popup window with the symbol siblings content
 action.ParameterInfo.text=_Parameter Info
 action.ParameterInfo.description=Show parameters of the method call at caret
+action.ToggleInlineHintsAction.text=Toggle parameter name hints
+action.ToggleInlineHintsAction.description=Toggle parameter name hints 
 action.ExpressionTypeInfo.text=_Expression Type
 action.ExpressionTypeInfo.description=Show type of the selected expression
 action.EditorContextInfo.text=_Context Info
@@ -1202,7 +1204,7 @@ action.Graph.print.preview=Print Preview
 
 action.SendFeedback.text=Submit _Feedback...
 action.SendFeedback.description=Submit feedback to the JetBrains Web site
-action.ShowLog.text=Show _Log in Explorer
+action.ShowLog.text=Show _Log in File Manager
 action.ShowLog.description=Opens folder with log file
 action.EditCustomProperties.text=Edit Custom Properties...
 action.EditCustomProperties.description=Opens an editor tab with a custom properties file
@@ -1474,6 +1476,8 @@ group.Vcs.Browse.text=Browse VCS Repository
 action.Graph.print.reset=Reset
 action.MarkExcludeRoot.text=Excluded
 action.UnmarkRoot.text=Unmark Root
+action.MarkAsContentRoot.text=Cancel Exclusion
+action.MarkAsContentRoot.description=Cancel exclusion for the selected directory to make its files processable by IDE's actions
 action.CreateLibraryFromFile.text=Add as Library...
 action.ImportModuleFromImlFile.text=Import Module
 action.ImportModuleFromImlFile.description=Import iml file as a module to the project
index af355de3126a6940e7d9f4a341db277cb7dfe80e..d295e219fef4e74cac1cb2f15d26c6bd8d34413b 100644 (file)
     <colorAndFontPanelFactory implementation="com.intellij.openapi.diff.impl.settings.DiffColorsPageFactory"/>
     <colorAndFontDescriptorProvider implementation="com.intellij.openapi.diff.impl.settings.DiffColorsPageFactory"/>
 
-    <fileTypeFactory implementation="com.intellij.diff.contents.DiffPsiFileType$TypeFactory"/>
     <lang.substitutor language="TEXT" implementationClass="com.intellij.diff.contents.DiffPsiFileType$Substitutor" order="first"/>
     <daemon.highlightInfoFilter implementation="com.intellij.diff.contents.DiffPsiFileType$HighlightFilter"/>
     <daemon.intentionActionFilter implementation="com.intellij.diff.contents.DiffPsiFileType$IntentionFilter"/>
index cac3ae55220b60ca956899c64caba1ee78ca0ff0..9a2c145584f2f1b6c996d2cfdbba72d43789e6db 100644 (file)
       <separator/>
       <add-to-group group-id="MainMenu" anchor="after" relative-to-action="GoToMenu"/>
     </group>
-
+    
+    <group id="ParameterNameHints" popup="true">
+      <action id="ToggleInlineHintsAction" class="com.intellij.analysis.actions.ToggleInlineHintsAction"/>
+      <action id="ReportExcessiveInlineHint" class="com.intellij.reporting.ReportExcessiveInlineHint"/>
+    </group>
+    
     <!-- Analyze -->
     <action id="SliceBackward" class="com.intellij.slicer.SliceBackwardAction"/>
     <action id="SliceForward" class="com.intellij.slicer.SliceForwardAction"/>
index d2182f033471f632f357458f911976e144be4f58..0d8def9d6273df72381a6ca9dd09f08489ef27e9 100644 (file)
@@ -30,7 +30,7 @@ import java.util.Set;
  */
 public interface FileIndex {
   /**
-   * Iterates all files and directories in the content.
+   * Iterates all files and directories under content roots skipping excluded and ignored files and directories.
    *
    * @param iterator the iterator receiving the files.
    * @return false if files processing was stopped ({@link ContentIterator#processFile(VirtualFile)} returned false)
@@ -38,8 +38,8 @@ public interface FileIndex {
   boolean iterateContent(@NotNull ContentIterator iterator);
 
   /**
-   * Iterates all files and directories in the content under directory <code>dir</code> (including the directory itself).
-   * Does not iterate anything if <code>dir</code> is not in the content.
+   * Iterates all files and directories in the content under directory <code>dir</code> (including the directory itself) skipping excluded
+   * and ignored files and directories. Does not iterate anything if <code>dir</code> is not in the content.
    *
    * @param dir      the directory the contents of which is iterated.
    * @param iterator the iterator receiving the files.
@@ -48,17 +48,14 @@ public interface FileIndex {
   boolean iterateContentUnderDirectory(@NotNull VirtualFile dir, @NotNull ContentIterator iterator);
 
   /**
-   * Returns true if <code>fileOrDir</code> is a file or directory under a content root of this
-   * project or module.
-   *
-   * @param fileOrDir the file or directory to check.
-   * @return true if the file or directory belongs to a content root, false otherwise.
+   * Returns {@code true} if {@code fileOrDir} is a file or directory under a content root of this project or module and not excluded or
+   * ignored.
    */
   boolean isInContent(@NotNull VirtualFile fileOrDir);
 
   /**
-   * Returns true if <code>file</code> is a source file which belongs to sources of the content.
-   * (Returns true for both source and test source).<p/>
+   * Returns {@code true} if {@code fileOrDir} is a file located under a sources, tests or resources root and not excluded or ignored.
+   * <p/>
    * Note that sometimes a file can belong to the content and be a source file but not belong to sources of the content.
    * This happens if sources of some library are located under the content (so they belong to the project content but not as sources).
    *
@@ -68,16 +65,12 @@ public interface FileIndex {
   boolean isContentSourceFile(@NotNull VirtualFile file);
 
   /**
-   * Returns true if <code>fileOrDir</code> is a file or directory from the content source.
-   * (Returns true for both source and test source).
-   *
-   * @param fileOrDir the file or directory to check.
-   * @return true if the file or directory belongs to a source or test source root, false otherwise.
+   * Returns {@code true} if {@code fileOrDir} is a file or directory located under a sources, tests or resources root and not excluded or ignored.
    */
   boolean isInSourceContent(@NotNull VirtualFile fileOrDir);
 
   /**
-   * Returns true if <code>fileOrDir</code> is a file or directory from the test content source
+   * Returns true if {@code fileOrDir} is a file or directory located under a test sources or resources root and not excluded or ignored.
    * <p>
    * Use this method when you really need to check whether the file is under test roots according to project configuration.
    * <p>
@@ -92,10 +85,7 @@ public interface FileIndex {
   boolean isInTestSourceContent(@NotNull VirtualFile fileOrDir);
 
   /**
-   * Returns true if <code>fileOrDir</code> is a file or directory from the source root which have
-   *
-   * @param fileOrDir the file or directory to check.
-   * @return true if the file or directory belongs to a source root of one of specified types, false otherwise
+   * Returns {@code true} if {@code fileOrDir} is a file or directory located under a source root of type from {@code rootTypes} set and not excluded or ignored
    */
   boolean isUnderSourceRootOfType(@NotNull VirtualFile fileOrDir, @NotNull Set<? extends JpsModuleSourceRootType<?>> rootTypes);
 }
index 8b3de586c61ee5f7f496ca2567cfb96f55032308..aa6a5aa35f5d8f1a5e1c719f387aa55a8776c51d 100644 (file)
@@ -712,7 +712,10 @@ public class SMTestRunnerResultsForm extends TestResultsPanel
   private void updateProgressOnTestDone() {
     int doneTestCount = myFinishedTestCount;
     // update progress
-    if (myTotalTestCount != 0 && !isUndefined()) {
+    if (isUndefined()) {
+      myStatusLine.setFraction(1.0);
+    }
+    else if (myTotalTestCount != 0) {
       // if total is set
       myStatusLine.setFraction((double) doneTestCount / myTotalTestCount);
     }
index a1bd02b83d5cff0bd1e93e3641c902491c75e23d..eee966b1386b870d1867c9123d3d30f390eb9832 100644 (file)
@@ -15,6 +15,7 @@
  */
 package com.intellij.projectView;
 
+import com.intellij.ide.projectView.ProjectViewSettings;
 import com.intellij.ide.projectView.impl.AbstractProjectTreeStructure;
 import com.intellij.ide.projectView.impl.AbstractProjectViewPSIPane;
 import com.intellij.openapi.Disposable;
@@ -25,7 +26,8 @@ import com.intellij.psi.PsiElement;
 import com.intellij.testFramework.ProjectViewTestUtil;
 import org.junit.Assert;
 
-public class TestProjectTreeStructure extends AbstractProjectTreeStructure implements Disposable {
+public class TestProjectTreeStructure extends AbstractProjectTreeStructure implements Disposable, ProjectViewSettings {
+  private boolean myShowExcludedFiles = true;
   protected boolean myShowMembers = false;
   protected boolean myHideEmptyMiddlePackages;
   protected boolean myFlattenPackages;
@@ -74,6 +76,11 @@ public class TestProjectTreeStructure extends AbstractProjectTreeStructure imple
     return myShowLibraryContents;
   }
 
+  @Override
+  public boolean isShowExcludedFiles() {
+    return myShowExcludedFiles;
+  }
+
   @Override
   public boolean isShowModules() {
     return true;
@@ -91,6 +98,10 @@ public class TestProjectTreeStructure extends AbstractProjectTreeStructure imple
     myFlattenPackages = flattenPackages;
   }
 
+  public void hideExcludedFiles() {
+    myShowExcludedFiles = false;
+  }
+
   public void setShowLibraryContents(boolean showLibraryContents) {
     myShowLibraryContents = showLibraryContents;
   }
index 7d19d9138691dad01d40fc0b0b576c5be86ce6d1..4390e42ba52544379564e89aa2e3e7c50f17c711 100644 (file)
@@ -2360,7 +2360,7 @@ public class UIUtil {
   public static HTMLEditorKit getHTMLEditorKit(boolean noGapsBetweenParagraphs) {
     Font font = getLabelFont();
     @NonNls String family = !SystemInfo.isWindows && font != null ? font.getFamily() : "Tahoma";
-    int size = font != null ? font.getSize() : JBUI.scale(11);
+    final int size = font != null ? font.getSize() : JBUI.scale(11);
 
     String customCss = String.format("body, div, p { font-family: %s; font-size: %s; }", family, size);
     if (noGapsBetweenParagraphs) {
@@ -2370,7 +2370,7 @@ public class UIUtil {
     final StyleSheet style = new StyleSheet();
     style.addStyleSheet(isUnderDarcula() ? (StyleSheet)UIManager.getDefaults().get("StyledEditorKit.JBDefaultStyle") : DEFAULT_HTML_KIT_CSS);
     style.addRule(customCss);
-    scaleStyleSheetFontSize(style);
+    scaleStyleSheetFontSize(style, size);
 
     return new HTMLEditorKit() {
 
@@ -2378,7 +2378,7 @@ public class UIUtil {
       public Document createDefaultDocument() {
         Document document = super.createDefaultDocument();
         if (document instanceof HTMLDocument) {
-          scaleStyleSheetFontSize(((HTMLDocument)document).getStyleSheet());
+          scaleStyleSheetFontSize(((HTMLDocument)document).getStyleSheet(), size);
         }
         return document;
       }
@@ -2390,17 +2390,11 @@ public class UIUtil {
     };
   }
 
-  private static void scaleStyleSheetFontSize(@Nullable StyleSheet styleSheet) {
-    if (styleSheet == null) {
-      return;
-    }
-    // 'baseFontSize' equals to javax.swing.text.html.StyleSheet.sizeMapDefault[3],
-    // where '3' == javax.swing.text.html.CSS.baseFontSizeIndex
-    // See javax.swing.text.html.StyleSheet.rebaseSizeMap()
-    int baseFontSize = 14;
-    int scaledBaseFontSize = JBUI.scaleFontSize(baseFontSize);
-    if (baseFontSize != scaledBaseFontSize) {
-      styleSheet.addRule("BASE_SIZE " + scaledBaseFontSize);
+  private static void scaleStyleSheetFontSize(@Nullable StyleSheet styleSheet, int bodyFontSize) {
+    // In compliance with javax.swing.text.html.StyleSheet logic, where 14pt font size is specified in
+    // javax/swing/text/html/default.css and javax.swing.text.html.StyleSheet.sizeMapDefault[3].
+    if (styleSheet != null) {
+      styleSheet.addRule("BASE_SIZE " + bodyFontSize);
     }
   }
 
index ffe43ec4bb99a510b30c6b6d96f92590a44403d3..0591dd7ac0bb3f56788244806f550c1244c62f0d 100644 (file)
@@ -37,7 +37,7 @@ import java.util.Map;
 
 public class GraphCommitCellRenderer extends ColoredTableCellRenderer {
   private static final Logger LOG = Logger.getInstance(GraphCommitCellRenderer.class);
-  private static final int MAX_GRAPH_WIDTH = 10;
+  private static final int MAX_GRAPH_WIDTH = 6;
 
   private static final int VERTICAL_PADDING = JBUI.scale(7);
 
index c7d2cbf70388ca6a8d3852d802645b92e83280ea..3f774dbbc813bca4ebaadf32258264efdecd14b7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006-2015 Dave Griffith, Bas Leijdekkers
+ * Copyright 2006-2016 Dave Griffith, Bas Leijdekkers
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@ import com.intellij.codeInspection.*;
 import com.intellij.codeInspection.reference.RefClass;
 import com.intellij.codeInspection.reference.RefEntity;
 import com.intellij.codeInspection.util.RefEntityAlphabeticalComparator;
-import com.intellij.psi.PsiAnonymousClass;
 import com.intellij.psi.PsiClass;
 import com.intellij.psi.PsiElement;
 import com.siyeh.InspectionGadgetsBundle;
@@ -51,8 +50,7 @@ public class CyclicClassDependencyInspection extends BaseGlobalInspection {
       return null;
     }
     final RefClass refClass = (RefClass)refEntity;
-    final PsiClass aClass = refClass.getElement();
-    if (aClass == null || aClass.getContainingClass() != null || aClass instanceof PsiAnonymousClass) {
+    if (refClass.isAnonymous() || refClass.isLocalClass() || refClass.isSyntheticJSP()) {
       return null;
     }
     final Set<RefClass> dependencies = DependencyUtils.calculateTransitiveDependenciesForClass(refClass);
@@ -79,6 +77,10 @@ public class CyclicClassDependencyInspection extends BaseGlobalInspection {
       errorString = InspectionGadgetsBundle.message("cyclic.class.dependency.problem.descriptor",
                                                     refEntity.getName(), Integer.valueOf(numMutualDependents));
     }
+    final PsiClass aClass = refClass.getElement();
+    if (aClass == null) {
+      return null;
+    }
     final PsiElement anchor = aClass.getNameIdentifier();
     if (anchor == null) return null;
     return new CommonProblemDescriptor[]{
index 302574bd4b032e1fffdd87acfa6276adf77ec1e2..c539cd96b92d70570b931f9a41c5e539935c3555 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006-2013 Dave Griffith, Bas Leijdekkers
+ * Copyright 2006-2016 Dave Griffith, Bas Leijdekkers
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -43,10 +43,8 @@ public class DependencyUtils {
   private DependencyUtils() {
   }
 
-  public static Set<RefClass> calculateDependenciesForClass(
-    RefClass refClass) {
-    final Set<RefClass> dependencies =
-      refClass.getUserData(DEPENDENCY_CLASSES_KEY);
+  public static Set<RefClass> calculateDependenciesForClass(RefClass refClass) {
+    final Set<RefClass> dependencies = refClass.getUserData(DEPENDENCY_CLASSES_KEY);
     if (dependencies != null) {
       return dependencies;
     }
@@ -57,40 +55,32 @@ public class DependencyUtils {
     return newDependencies;
   }
 
-  @SuppressWarnings({"MethodWithMultipleLoops"})
-  static void tabulateDependencyClasses(RefJavaElement element,
-                                        Set<RefClass> dependencies) {
-    final Collection<RefElement> references = element.getOutReferences();
-    final RefJavaUtil refUtil = RefJavaUtil.getInstance();
-    for (RefElement reference : references) {
-      final RefClass refClass = refUtil.getTopLevelClass(reference);
-      if (refClass != null) {
-        dependencies.add(refClass);
-      }
-    }
-    final Collection<RefClass> typeReferences =
-      element.getOutTypeReferences();
-    for (RefElement reference : typeReferences) {
-      final RefClass refClass = refUtil.getTopLevelClass(reference);
-      if (refClass != null) {
-        dependencies.add(refClass);
-      }
-    }
+  private static void tabulateDependencyClasses(RefJavaElement element, Set<RefClass> dependencies) {
+    addOwnerClassesToSet(element.getOutReferences(), dependencies);
+    addOwnerClassesToSet(element.getOutTypeReferences(), dependencies);
     final List<RefEntity> children = element.getChildren();
     if (children == null) {
       return;
     }
     for (RefEntity child : children) {
-      if (child instanceof RefJavaElement) {
+      if (child instanceof RefJavaElement && !(child instanceof RefClass)) {
         tabulateDependencyClasses((RefJavaElement)child, dependencies);
       }
     }
   }
 
-  public static Set<RefClass> calculateTransitiveDependenciesForClass(
-    RefClass refClass) {
-    final Set<RefClass> dependencies =
-      refClass.getUserData(TRANSITIVE_DEPENDENCY_CLASSES_KEY);
+  private static void addOwnerClassesToSet(Collection<? extends RefElement> references, Set<RefClass> set) {
+    final RefJavaUtil refUtil = RefJavaUtil.getInstance();
+    for (RefElement reference : references) {
+      final RefClass refClass = (reference instanceof RefClass) ? (RefClass)reference : refUtil.getOwnerClass(reference);
+      if (refClass != null && !refClass.isAnonymous() && !refClass.isLocalClass()) {
+        set.add(refClass);
+      }
+    }
+  }
+
+  public static Set<RefClass> calculateTransitiveDependenciesForClass(RefClass refClass) {
+    final Set<RefClass> dependencies = refClass.getUserData(TRANSITIVE_DEPENDENCY_CLASSES_KEY);
     if (dependencies != null) {
       return dependencies;
     }
@@ -122,51 +112,36 @@ public class DependencyUtils {
   }
 
   public static Set<RefClass> calculateDependentsForClass(RefClass refClass) {
-    final Set<RefClass> dependents =
-      refClass.getUserData(DEPENDENT_CLASSES_KEY);
+    final Set<RefClass> dependents = refClass.getUserData(DEPENDENT_CLASSES_KEY);
     if (dependents != null) {
       return dependents;
     }
     final Set<RefClass> newDependents = new HashSet<>();
     tabulateDependentClasses(refClass, newDependents);
-    final Set<RefElement> typeReferences = refClass.getInTypeReferences();
-    final RefJavaUtil refUtil = RefJavaUtil.getInstance();
-    for (RefElement typeReference : typeReferences) {
-      final RefClass referencingClass =
-        refUtil.getTopLevelClass(typeReference);
-      newDependents.add(referencingClass);
-    }
     newDependents.remove(refClass);
     refClass.putUserData(DEPENDENT_CLASSES_KEY, newDependents);
     return newDependents;
   }
 
-  @SuppressWarnings({"MethodWithMultipleLoops"})
-  private static void tabulateDependentClasses(RefElement element,
-                                               Set<RefClass> dependents) {
-    final Collection<RefElement> references = element.getInReferences();
-    final RefJavaUtil refUtil = RefJavaUtil.getInstance();
-    for (RefElement reference : references) {
-      final RefClass refClass = refUtil.getTopLevelClass(reference);
-      if (refClass != null) {
-        dependents.add(refClass);
-      }
+  private static void tabulateDependentClasses(RefElement element, Set<RefClass> dependents) {
+    addOwnerClassesToSet(element.getInReferences(), dependents);
+    if (element instanceof RefClass) {
+      final RefClass refClass = (RefClass)element;
+      addOwnerClassesToSet(refClass.getInTypeReferences(), dependents);
     }
     final List<RefEntity> children = element.getChildren();
     if (children == null) {
       return;
     }
     for (RefEntity child : children) {
-      if (child instanceof RefElement) {
+      if (child instanceof RefElement && !(child instanceof RefClass)) {
         tabulateDependentClasses((RefElement)child, dependents);
       }
     }
   }
 
-  public static Set<RefClass> calculateTransitiveDependentsForClass(
-    RefClass refClass) {
-    final Set<RefClass> dependents =
-      refClass.getUserData(TRANSITIVE_DEPENDENT_CLASSES_KEY);
+  public static Set<RefClass> calculateTransitiveDependentsForClass(RefClass refClass) {
+    final Set<RefClass> dependents = refClass.getUserData(TRANSITIVE_DEPENDENT_CLASSES_KEY);
     if (dependents != null) {
       return dependents;
     }
@@ -205,15 +180,13 @@ public class DependencyUtils {
       return dependencies;
     }
     final Set<RefPackage> newDependencies = new HashSet<>();
-
     tabulateDependencyPackages(refPackage, newDependencies);
     newDependencies.remove(refPackage);
     refPackage.putUserData(DEPENDENCY_PACKAGES_KEY, newDependencies);
     return newDependencies;
   }
 
-  static void tabulateDependencyPackages(RefEntity entity,
-                                         Set<RefPackage> dependencies) {
+  private static void tabulateDependencyPackages(RefEntity entity, Set<RefPackage> dependencies) {
     if (entity instanceof RefElement) {
       final RefElement element = (RefElement)entity;
       final Collection<RefElement> references = element.getOutReferences();
@@ -249,7 +222,7 @@ public class DependencyUtils {
     return newDependents;
   }
 
-  static void tabulateDependentPackages(RefEntity entity, Set<RefPackage> dependents) {
+  private static void tabulateDependentPackages(RefEntity entity, Set<RefPackage> dependents) {
     if (entity instanceof RefElement) {
       final RefElement element = (RefElement)entity;
       final Collection<RefElement> references = element.getInReferences();
index d75c4d2e2d958a40b3b17152acaaad38394f0e29..0b7f839ac8dea84f7efbcf1c258e3bb1877b2111 100644 (file)
@@ -1,5 +1,12 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <problems>
+  <problem>
+    <file>Cyclic.java</file>
+    <line>6</line>
+    <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cyclic class dependency</problem_class>
+    <description>Class 'Cyclic' is cyclically dependent on classes 'com.siyeh.igtest.dependency.cyclic_class_dependency.src.Base' and 'com.siyeh.igtest.dependency.cyclic_class_dependency.src.Top'</description>
+  </problem>
+
   <problem>
     <file>Cyclic.java</file>
     <line>17</line>
 
   <problem>
     <file>Cyclic.java</file>
-    <line>6</line>
+    <line>52</line>
     <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cyclic class dependency</problem_class>
-    <description>Class 'Cyclic' is cyclically dependent on classes 'com.siyeh.igtest.dependency.cyclic_class_dependency.src.Base' and 'com.siyeh.igtest.dependency.cyclic_class_dependency.src.Top'</description>
+    <description>Class 'Inner1' is cyclically dependent on class 'com.siyeh.igtest.dependency.cyclic_class_dependency.src.Outer.Inner2'</description>
+  </problem>
+
+  <problem>
+    <file>Cyclic.java</file>
+    <line>55</line>
+    <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cyclic class dependency</problem_class>
+    <description>Class 'Inner2' is cyclically dependent on class 'com.siyeh.igtest.dependency.cyclic_class_dependency.src.Outer.Inner1'</description>
   </problem>
 </problems>
\ No newline at end of file
index e8f750c99fa3d20fd87c287517e3f5a09641d00b..de36b6011c41129bdd188368d27d7f9175cab074 100644 (file)
@@ -42,3 +42,17 @@ enum MyEnum {
 
   abstract int value();
 }
+class Outer {
+
+  void m() {
+    class Local {}
+    class Local2 extends Outer {}
+  }
+
+  class Inner1 {
+    Inner2 field;
+  }
+  class Inner2 {
+    Inner1 field;
+  }
+}
\ No newline at end of file
index e86a1970530601f282348b7d0be0cf860aa9e5a5..87fdcfef51b3c1721f6342fa666fabf7821e4a0e 100644 (file)
@@ -185,4 +185,21 @@ class TryIdenticalCatches {
       System.out.println(e);
     }
   }
+}
+class TestInspection {
+  public void foo() throws MyException {
+    try {
+      toString();
+    } catch (IllegalArgumentException e) {
+      throw new MyException(e);
+    } catch (IllegalStateException e) {
+      throw new MyException(e);
+    }
+  }
+
+  private static class MyException extends Exception {
+    public MyException(IllegalArgumentException e) {}
+
+    public MyException(IllegalStateException e) {}
+  }
 }
\ No newline at end of file
index 05fce429d02e53515ec96b585baa2bf25bf96718..ff838abeae7c95663f562b82a85288590308f34a 100644 (file)
@@ -188,4 +188,21 @@ class TryIdenticalCatches {
       System.out.println(e);
     }
   }
+}
+class TestInspection {
+  public void foo() throws MyException {
+    try {
+      toString();
+    } catch (IllegalArgumentException e) {
+      throw new MyException(e);
+    } catch (IllegalStateException e) {
+      throw new MyException(e);
+    }
+  }
+
+  private static class MyException extends Exception {
+    public MyException(IllegalArgumentException e) {}
+
+    public MyException(IllegalStateException e) {}
+  }
 }
\ No newline at end of file
index c6035677036e298002927b0ef1205d5d86e85314..853aec5cc6c25fd002560f4aab6cd4dd29c22c04 100644 (file)
@@ -31,45 +31,41 @@ public interface KeyboardShortcut extends DomElement {
 
        /**
         * Returns the value of the first-keystroke child.
-        * Attribute first-keystroke
+        * Attribute {@code first-keystroke}
         * @return the value of the first-keystroke child.
         */
        @NotNull
        @Required
        GenericAttributeValue<String> getFirstKeystroke();
 
-
        /**
         * Returns the value of the keymap child.
-        * Attribute keymap
+        * Attribute {@code keymap}
         * @return the value of the keymap child.
         */
        @NotNull
        @Required
        GenericAttributeValue<String> getKeymap();
 
-
        /**
         * Returns the value of the use-shortcut-of child.
-        * Attribute use-shortcut-of
+        * Attribute {@code use-shortcut-of}
         * @return the value of the use-shortcut-of child.
         */
        @NotNull
        GenericAttributeValue<String> getUseShortcutOf();
 
-
        /**
         * Returns the value of the second-keystroke child.
-        * Attribute second-keystroke
+        * Attribute {@code second-keystroke}
         * @return the value of the second-keystroke child.
         */
        @NotNull
        GenericAttributeValue<String> getSecondKeystroke();
 
-
         /**
          * Returns the value of the should current shortcut be removed or not.
-         * Attribute remove option
+         * Attribute {@code remove}
          * @return the value of the should current shortcut be removed or not.
          */
         @NotNull
@@ -77,10 +73,9 @@ public interface KeyboardShortcut extends DomElement {
 
         /**
          * Returns the value of the should all previous shortcuts be removed by that one or not.
-         * Attribute remove option
+         * Attribute {@code replace-all}
          * @return the value of the should all previous shortcuts be removed by that one or not.
          */
         @NotNull
         GenericAttributeValue<String> getReplaceAll();
-
 }
index fc0544ac6f1affbb1fbaa98a754a1716ccb9c837..69e0d8f5ef82361af291cc1ff724da4e7a59186a 100644 (file)
@@ -31,22 +31,35 @@ public interface MouseShortcut extends DomElement {
 
        /**
         * Returns the value of the keymap child.
-        * Attribute keymap
+        * Attribute {@code keymap}
         * @return the value of the keymap child.
         */
        @NotNull
        @Required
        GenericAttributeValue<String> getKeymap();
 
-
        /**
         * Returns the value of the keystroke child.
-        * Attribute keystroke
+        * Attribute {@code keystroke}
         * @return the value of the keystroke child.
         */
        @NotNull
        @Required
        GenericAttributeValue<String> getKeystroke();
 
+        /**
+         * Returns the value of the should current shortcut be removed or not.
+         * Attribute {@code remove}
+         * @return the value of the should current shortcut be removed or not.
+         */
+        @NotNull
+        GenericAttributeValue<String> getRemove();
 
+        /**
+         * Returns the value of the should all previous shortcuts be removed by that one or not.
+         * Attribute {@code replace-all}
+         * @return the value of the should all previous shortcuts be removed by that one or not.
+         */
+        @NotNull
+        GenericAttributeValue<String> getReplaceAll();
 }
index 4f4a924a583f8da227a0406b684759ee56e6f71d..ddaebc48144e15b4c15609854d1678a5d56ab660 100644 (file)
@@ -87,6 +87,13 @@ public interface TransformationContext {
     return getAnnotation(fqn) != null;
   }
 
+  default boolean isInheritor(@NotNull String fqn) {
+    PsiClass baseClass = getPsiFacade().findClass(fqn, getResolveScope());
+    return baseClass != null && isInheritor(baseClass);
+  }
+
+  boolean isInheritor(@NotNull PsiClass baseClass);
+
   @NotNull
   Collection<PsiMethod> findMethodsByName(@NotNull String name, boolean checkBases);
 
index 726003266e4e0fb031e376f31d6980dcfad97593..87b1bc329af50622ec357dca5a34d03ada9c3f08 100644 (file)
@@ -122,6 +122,21 @@ public class TransformationContextImpl implements TransformationContext {
     return PsiImplUtil.getAnnotation(getCodeClass(), fqn);
   }
 
+  @Override
+  public boolean isInheritor(@NotNull PsiClass baseClass) {
+    if (getManager().areElementsEquivalent(getCodeClass(), baseClass)) return false;
+    if (getCodeClass().isInterface() && !baseClass.isInterface()) return false;
+
+    for (PsiClassType superType : getSuperTypes()) {
+      PsiClass superClass = superType.resolve();
+      if (superClass == null) continue;
+      if (getManager().areElementsEquivalent(superClass, baseClass)) return true;
+      if (superClass.isInheritor(baseClass, true)) return true;
+    }
+
+    return false;
+  }
+
   @NotNull
   @Override
   public Collection<PsiMethod> findMethodsByName(@NotNull String name, boolean checkBases) {
index b4123606a8da206d7da9f85ff8e5c840699ec532..4cc51f704f162801680e4b92d221d32e50b28965 100644 (file)
@@ -496,6 +496,11 @@ public class JavaFXHighlightingTest extends AbstractJavaFXTestCase {
     doTest();
   }
 
+  public void testFxIdUsedInSameNode() throws Exception {
+    myFixture.configureByFiles(getTestName(true) + ".fxml", getTestName(false) + ".java");
+    doTest();
+  }
+
   private void doTest() throws Exception {
     myFixture.testHighlighting(false, false, false, getTestName(true) + ".fxml");
   }
index ec690bc93ddbcf73d969b1e749df350bcb3403ab..7029408deca3cb71d275088989f6bc99b8d6bec8 100644 (file)
@@ -767,21 +767,20 @@ public class JavaFxPsiUtil {
   public static Map<String, XmlAttributeValue> collectFileIds(@Nullable final XmlTag currentTag) {
     if (currentTag == null) return Collections.emptyMap();
     final PsiFile containingFile = currentTag.getContainingFile();
-    final XmlAttribute currentIdAttribute = currentTag.getAttribute(FxmlConstants.FX_ID);
-    return collectFileIds(containingFile, currentIdAttribute != null ? currentIdAttribute.getValue() : null);
+    return collectFileIds(containingFile, false);
   }
 
   @NotNull
-  public static Map<String, XmlAttributeValue> collectFileIds(@Nullable PsiFile psiFile, @Nullable String skipFxId) {
+  public static Map<String, XmlAttributeValue> collectFileIds(@Nullable PsiFile psiFile, boolean skipController) {
     if (!(psiFile instanceof XmlFile)) return Collections.emptyMap();
     final XmlTag rootTag = ((XmlFile)psiFile).getRootTag();
     if (rootTag == null) return Collections.emptyMap();
 
     final Map<String, XmlAttributeValue> cachedIds = CachedValuesManager
       .getCachedValue(rootTag, () -> new CachedValueProvider.Result<>(prepareFileIds(rootTag), PsiModificationTracker.MODIFICATION_COUNT));
-    if (skipFxId != null && cachedIds.containsKey(skipFxId)) {
+    if (skipController && cachedIds.containsKey(FxmlConstants.CONTROLLER)) {
       final Map<String, XmlAttributeValue> filteredIds = new THashMap<>(cachedIds);
-      filteredIds.remove(skipFxId);
+      filteredIds.remove(FxmlConstants.CONTROLLER);
       return filteredIds;
     }
     return cachedIds;
diff --git a/plugins/javaFX/testData/highlighting/FxIdUsedInSameNode.java b/plugins/javaFX/testData/highlighting/FxIdUsedInSameNode.java
new file mode 100644 (file)
index 0000000..4b90a9d
--- /dev/null
@@ -0,0 +1,7 @@
+import javafx.fxml.FXML;
+import javafx.scene.layout.HBox;
+
+public class FxIdUsedInSameNode {
+  @FXML
+  private HBox navigationPane;
+}
\ No newline at end of file
diff --git a/plugins/javaFX/testData/highlighting/fxIdUsedInSameNode.fxml b/plugins/javaFX/testData/highlighting/fxIdUsedInSameNode.fxml
new file mode 100644 (file)
index 0000000..b34ac49
--- /dev/null
@@ -0,0 +1,9 @@
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.layout.GridPane?>
+<?import javafx.scene.layout.HBox?>
+<GridPane fx:controller="FxIdUsedInSameNode"
+          xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
+  <HBox fx:id="navigationPane" id="navigationPane" managed="${navigationPane.visible}">
+    <Label text="Hi"/>
+  </HBox>
+</GridPane>
\ No newline at end of file
index e61485813422ff5b0cbbc8f764e14bee9653ed8c..3f167adddb8fb3d1aff0c86216375002ddd05075 100644 (file)
       <add-to-group group-id="WelcomeScreen.QuickStart" anchor="first"/>
     </group>
 
-    <action id="MarkSourceRoot" class="com.intellij.ide.projectView.actions.MarkJavaSourceRootAction">
+    <group>
+      <action id="MarkSourceRoot" class="com.intellij.ide.projectView.actions.MarkJavaSourceRootAction"/>
+      <action id="MarkExcludeRoot" class="com.intellij.ide.projectView.actions.MarkExcludeRootAction"/>
+      <action id="MarkAsContentRoot" class="com.intellij.ide.projectView.actions.MarkAsContentRootAction"/>
+      <action id="UnmarkRoot" class="com.intellij.ide.projectView.actions.UnmarkRootAction"/>
       <add-to-group group-id="MarkRootGroup"/>
-    </action>
-    <action id="MarkExcludeRoot" class="com.intellij.ide.projectView.actions.MarkExcludeRootAction" icon="AllIcons.Modules.ExcludeRoot">
-      <add-to-group group-id="MarkRootGroup"/>
-    </action>
-    <action id="UnmarkRoot" class="com.intellij.ide.projectView.actions.UnmarkRootAction">
-      <add-to-group group-id="MarkRootGroup"/>
-    </action>
+    </group>
 
     <action overrides="true" id="ForceStepInto" class="com.intellij.openapi.actionSystem.EmptyAction"/>
 
index 9d39aceee2b47a4f3ac4047fb8b9ab79e06092cd..3f0df093112dddf10afd247d339ef8eb9fea047b 100644 (file)
@@ -43,6 +43,15 @@ import static com.intellij.openapi.util.text.StringUtil.startsWith;
  */
 public class PythonStringUtil {
   private static final ImmutableList<String> QUOTES = ImmutableList.of("'''", "\"\"\"", "'", "\"");
+  /**
+   * Valid string prefix characters (lowercased) as defined in Python lexer.
+   */
+  public static final String PREFIX_CHARACTERS = "ubcrf";
+  
+  /**
+   * Maximum length of a string prefix as defined in Python lexer.
+   */
+  public static final int MAX_PREFIX_LENGTH = 3;
 
   private PythonStringUtil() {
   }
@@ -199,24 +208,8 @@ public class PythonStringUtil {
    */
   @Nullable
   public static Pair<String, String> getQuotes(@NotNull final String text) {
-    boolean start = true;
-    int pos = 0;
-    for (int i = 0; i < text.length(); i++) {
-      final char c = Character.toLowerCase(text.charAt(i));
-      if (start) {
-        if (c == 'u' || c == 'r' || c == 'b') {
-          pos = i + 1;
-        }
-        else {
-          start = false;
-        }
-      }
-      else {
-        break;
-      }
-    }
-    final String prefix = text.substring(0, pos);
-    final String mainText = text.substring(pos);
+    final String prefix = getPrefix(text);
+    final String mainText = text.substring(prefix.length());
     for (String quote : QUOTES) {
       final Pair<String, String> quotes = getQuotes(mainText, prefix, quote);
       if (quotes != null) {
@@ -226,6 +219,67 @@ public class PythonStringUtil {
     return null;
   }
 
+  /**
+   * Finds the end offset of the string prefix starting from {@code startOffset} in the given char sequence. 
+   * String prefix may contain only up to {@link #MAX_PREFIX_LENGTH} characters from {@link #PREFIX_CHARACTERS}
+   * (case insensitively).  
+   * 
+   * @return end offset of found string prefix
+   */
+  public static int getPrefixEndOffset(@NotNull CharSequence text, int startOffset) {
+    int offset;
+    for (offset = startOffset; offset < Math.min(startOffset + MAX_PREFIX_LENGTH, text.length()); offset++) {
+      if (PREFIX_CHARACTERS.indexOf(Character.toLowerCase(text.charAt(offset))) < 0) {
+        break;
+      }
+    }
+    return offset;
+  }
+
+  @NotNull
+  public static String getPrefix(@NotNull CharSequence text) {
+    return getPrefix(text, 0);
+  }
+
+  /**
+   * Extracts string prefix from the given char sequence using {@link #getPrefixEndOffset(CharSequence, int)}.
+   *
+   * @return extracted string prefix
+   * @see #getPrefixEndOffset(CharSequence, int)
+   */
+  @NotNull
+  public static String getPrefix(@NotNull CharSequence text, int startOffset) {
+    return text.subSequence(startOffset, getPrefixEndOffset(text, startOffset)).toString();
+  }
+
+  /**
+   * @return whether the given prefix contains either 'u' or 'U' character
+   */
+  public static boolean isUnicodePrefix(@NotNull String prefix) {
+    return StringUtil.indexOfIgnoreCase(prefix, 'u', 0) >= 0;
+  }
+
+  /**
+   * @return whether the given prefix contains either 'b' or 'B' character
+   */
+  public static boolean isBytesPrefix(@NotNull String prefix) {
+    return StringUtil.indexOfIgnoreCase(prefix, 'b', 0) >= 0;
+  }
+
+  /**
+   * @return whether the given prefix contains either 'r' or 'R' character
+   */
+  public static boolean isRawPrefix(@NotNull String prefix) {
+    return StringUtil.indexOfIgnoreCase(prefix, 'r', 0) >= 0;
+  }
+
+  /**
+   * @return whether the given prefix contains either 'f' or 'F' character
+   */
+  public static boolean isFormattedPrefix(@NotNull String prefix) {
+    return StringUtil.indexOfIgnoreCase(prefix, 'f', 0) >= 0;
+  }
+
   @Nullable
   private static Pair<String, String> getQuotes(@NotNull String text, @NotNull String prefix, @NotNull String quote) {
     final int length = text.length();
index 7c59ee522ab27b71635124bb09ebb6d5e91b1436..f342526b24f3e486b3be275e9618eae1a0410afe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2016 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,8 +17,8 @@ package com.jetbrains.python.psi;
 
 import org.jetbrains.annotations.Nullable;
 
-import java.math.BigInteger;
 import java.math.BigDecimal;
+import java.math.BigInteger;
 
 public interface PyNumericLiteralExpression extends PyLiteralExpression {
   /**
@@ -33,11 +33,13 @@ public interface PyNumericLiteralExpression extends PyLiteralExpression {
    * Returns the value of this literal as a {@code BigInteger} (with any
    * fraction truncated).
    */
+  @Nullable
   BigInteger getBigIntegerValue();
 
   /**
    * Returns the exact value of this literal.
    */
+  @Nullable
   BigDecimal getBigDecimalValue();
 
   boolean isIntegerLiteral();
index 5ba2c88db133216072d4ec6be6908eed74ae0c4c..cb517aefcf47d5453c21dc0ef1c9603a9d3437de 100644 (file)
@@ -17,10 +17,12 @@ package com.jetbrains.python.codeInsight.fstrings;
 
 import com.intellij.openapi.util.TextRange;
 import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.containers.ContainerUtil;
 import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -29,12 +31,14 @@ import java.util.List;
 public class FStringParser {
   private final String myNodeText;
   private final TextRange myNodeContentRange;
-  private final List<FragmentOffsets> myFragments = new ArrayList<>();
+  private final List<Fragment> myFragments = new ArrayList<>();
+  private final List<Integer> mySingleRightBraces = new ArrayList<>();
 
-  public static List<FragmentOffsets> parse(@NotNull String nodeText) {
+  @NotNull
+  public static ParseResult parse(@NotNull String nodeText) {
     final FStringParser parser = new FStringParser(nodeText);
     parser.parseTopLevel();
-    return parser.myFragments;
+    return new ParseResult(parser.mySingleRightBraces, parser.myFragments);
   }
 
   private FStringParser(@NotNull String nodeText) {
@@ -63,6 +67,10 @@ public class FStringParser {
         offset = parseFragment(offset, 1);
         continue;
       }
+      // Will be marked as errors
+      else if (c1 == '}') {
+        mySingleRightBraces.add(offset);
+      }
       offset++;
     }
   }
@@ -76,7 +84,10 @@ public class FStringParser {
     int bracesBalance = 0;
     char stringLiteralQuote = '\0';
     int quotesNum = 0;
+    
+    // Used for f-strings validation
     boolean containsNamedUnicodeEscape = false;
+    int firstHashOffset = -1;
 
     int offset = leftBraceOffset + 1;
     while (offset < myNodeContentRange.getEndOffset()) {
@@ -112,6 +123,9 @@ public class FStringParser {
           offset += quotesNum;
           continue;
         }
+        else if (c1 == '#' && firstHashOffset == -1) {
+          firstHashOffset = offset;
+        }
         else if (c1 == '{' || c1 == '[' || c1 == '(') {
           bracesBalance++;
         }
@@ -141,7 +155,12 @@ public class FStringParser {
     if (contentEndOffset == -1) {
       contentEndOffset = offset;
     }
-    myFragments.add(new FragmentOffsets(leftBraceOffset, contentEndOffset, rightBraceOffset, containsNamedUnicodeEscape));
+    myFragments.add(new Fragment(leftBraceOffset, 
+                                 contentEndOffset, 
+                                 rightBraceOffset, 
+                                 containsNamedUnicodeEscape, 
+                                 firstHashOffset,
+                                 depth));
     return offset;
   }
 
@@ -153,20 +172,30 @@ public class FStringParser {
     return offset;
   }
 
-  public static class FragmentOffsets {
+  public static class Fragment {
     private final int myLeftBraceOffset;
     private final int myRightBraceOffset;
     private final int myContentEndOffset;
     private final boolean myContainsNamedUnicodeEscape;
-
-    private FragmentOffsets(int leftBraceOffset, int contentEndOffset, int rightBraceOffset, boolean escape) {
-      assert contentEndOffset > leftBraceOffset;
-      assert rightBraceOffset < 0 || (contentEndOffset <= rightBraceOffset && leftBraceOffset < rightBraceOffset);
+    private final int myFirstHashOffset;
+    private int myDepth;
+
+    private Fragment(int leftBraceOffset,
+                     int contentEndOffset,
+                     int rightBraceOffset,
+                     boolean containsUnicodeEscape,
+                     int firstHashOffset, 
+                     int depth) {
+      assert leftBraceOffset < contentEndOffset;
+      assert rightBraceOffset < 0 || contentEndOffset <= rightBraceOffset;
+      assert firstHashOffset < 0 || leftBraceOffset < firstHashOffset && firstHashOffset < contentEndOffset;
 
       myLeftBraceOffset = leftBraceOffset;
       myRightBraceOffset = rightBraceOffset;
       myContentEndOffset = contentEndOffset;
-      myContainsNamedUnicodeEscape = escape;
+      myContainsNamedUnicodeEscape = containsUnicodeEscape;
+      myFirstHashOffset = firstHashOffset;
+      myDepth = depth;
     }
 
     public int getLeftBraceOffset() {
@@ -185,9 +214,37 @@ public class FStringParser {
       return myContainsNamedUnicodeEscape;
     }
 
+    public int getFirstHashOffset() {
+      return myFirstHashOffset;
+    }
+
+    public int getDepth() {
+      return myDepth;
+    }
+
     @NotNull
     public TextRange getContentRange() {
       return TextRange.create(myLeftBraceOffset + 1, myContentEndOffset);
     }
   }
+  
+  public static class ParseResult {
+    private final List<Integer> mySingleRightBraces;
+    private final List<Fragment> myFragments;
+
+    private ParseResult(@NotNull List<Integer> singleRightBraces, @NotNull List<Fragment> fragments) {
+      mySingleRightBraces = singleRightBraces;
+      myFragments = ContainerUtil.sorted(fragments, (f1, f2) -> f1.getLeftBraceOffset() - f2.getLeftBraceOffset());;
+    }
+
+    @NotNull
+    public List<Integer> getSingleRightBraces() {
+      return Collections.unmodifiableList(mySingleRightBraces);
+    }
+
+    @NotNull
+    public List<Fragment> getFragments() {
+      return Collections.unmodifiableList(myFragments);
+    }
+  }
 }
index 9851f41b263930eb278e63642b291164d903ec6c..365d40cd20c59f47b374a688d3c08f5b5d1ffacb 100644 (file)
@@ -20,7 +20,7 @@ import com.intellij.lang.Language;
 import com.intellij.lang.injection.MultiHostRegistrar;
 import com.intellij.psi.PsiElement;
 import com.jetbrains.python.codeInsight.PyInjectorBase;
-import com.jetbrains.python.codeInsight.fstrings.FStringParser.FragmentOffsets;
+import com.jetbrains.python.codeInsight.fstrings.FStringParser.Fragment;
 import com.jetbrains.python.documentation.doctest.PyDocstringLanguageDialect;
 import com.jetbrains.python.psi.PyStringLiteralExpression;
 import com.jetbrains.python.psi.PyUtil.StringNodeInfo;
@@ -45,7 +45,7 @@ public class PyFStringsInjector extends PyInjectorBase {
     
     for (ASTNode node : pyString.getStringNodes()) {
       final int relNodeOffset = node.getTextRange().getStartOffset() - pyString.getTextRange().getStartOffset();
-      for (FragmentOffsets offsets : getInjectionRanges(node)) {
+      for (Fragment offsets : getInjectionRanges(node)) {
         if (offsets.containsNamedUnicodeEscape()) continue;
         registrar.startInjecting(PyDocstringLanguageDialect.getInstance());
         registrar.addPlace(null, null, pyString, offsets.getContentRange().shiftRight(relNodeOffset));
@@ -55,10 +55,10 @@ public class PyFStringsInjector extends PyInjectorBase {
   }
 
   @NotNull
-  private static List<FragmentOffsets> getInjectionRanges(@NotNull ASTNode node) {
+  private static List<Fragment> getInjectionRanges(@NotNull ASTNode node) {
     final StringNodeInfo nodeInfo = new StringNodeInfo(node);
     if (nodeInfo.isFormatted()) {
-      return FStringParser.parse(node.getText());
+      return FStringParser.parse(node.getText()).getFragments();
     }
     return Collections.emptyList();
   }
index 86e89630cc84c4bc813bf461a48cc2dbcc70625f..5f3248a5fca1fe339ebb35bd48a4db9a7c95e614 100644 (file)
@@ -22,6 +22,7 @@ import com.intellij.openapi.editor.highlighter.HighlighterIterator;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.tree.IElementType;
 import com.intellij.psi.tree.TokenSet;
+import com.jetbrains.python.PythonStringUtil;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Arrays;
@@ -60,7 +61,7 @@ public class BaseQuoteHandler extends SimpleTokenSetQuoteHandler implements Mult
       }
       if (myLiteralTokenSet.contains(iterator.getTokenType())) {
         int start = iterator.getStart();
-        if (offset - start <= 2) {
+        if (offset - start <= PythonStringUtil.MAX_PREFIX_LENGTH) {
           if (getLiteralStartOffset(text, start) == offset) return true;
         }
       }
@@ -88,11 +89,7 @@ public class BaseQuoteHandler extends SimpleTokenSetQuoteHandler implements Mult
   }
 
   private static int getLiteralStartOffset(CharSequence text, int start) {
-    int index = start;
-    while (index < start + 2 && "URBF".indexOf(Character.toUpperCase(text.charAt(index))) >= 0) {
-      index++;
-    }
-    return index;
+    return PythonStringUtil.getPrefixEndOffset(text, start);
   }
 
   @Override
index 0ac9e3b6e3e6f563628550f0b787806978d839b0..31e1f17de58d20b9df2203b3db0c98698399cba3 100644 (file)
@@ -19,11 +19,15 @@ import com.intellij.codeInsight.FileModificationService;
 import com.intellij.codeInsight.controlflow.ControlFlowUtil;
 import com.intellij.codeInsight.controlflow.Instruction;
 import com.intellij.codeInspection.*;
+import com.intellij.lang.injection.InjectedLanguageManager;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.command.CommandProcessor;
 import com.intellij.openapi.extensions.Extensions;
 import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.TextRange;
 import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
 import com.intellij.psi.util.PsiTreeUtil;
 import com.jetbrains.python.PyBundle;
 import com.jetbrains.python.PyNames;
@@ -44,9 +48,12 @@ import com.jetbrains.python.psi.resolve.PyResolveContext;
 import com.jetbrains.python.psi.search.PyOverridingMethodsSearch;
 import com.jetbrains.python.psi.search.PySuperMethodsSearch;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.*;
 
+import static com.jetbrains.python.psi.PyUtil.as;
+
 /**
  * @author oleg
  */
@@ -95,6 +102,38 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor {
     collectUsedReads(owner);
   }
 
+  @Override
+  public void visitPyStringLiteralExpression(PyStringLiteralExpression pyString) {
+    final ScopeOwner owner = ScopeUtil.getScopeOwner(pyString);
+    if (owner != null && !(owner instanceof PsiFile)) {
+      final PyStatement instrAnchor = PsiTreeUtil.getParentOfType(pyString, PyStatement.class);
+      if (instrAnchor == null) return;
+      final Instruction[] instructions = ControlFlowCache.getControlFlow(owner).getInstructions();
+      final int startInstruction = ControlFlowUtil.findInstructionNumberByElement(instructions, instrAnchor);
+      if (startInstruction < 0) return;
+      final Project project = pyString.getProject();
+      final List<Pair<PsiElement, TextRange>> pairs = InjectedLanguageManager.getInstance(project).getInjectedPsiFiles(pyString);
+      if (pairs != null) {
+        for (Pair<PsiElement, TextRange> pair : pairs) {
+          pair.getFirst().accept(new PyRecursiveElementVisitor() {
+            @Override
+            public void visitPyReferenceExpression(PyReferenceExpression expr) {
+              final PyExpression qualifier = expr.getQualifier();
+              if (qualifier != null) {
+                qualifier.accept(this);
+                return;
+              }
+              final String name = expr.getName();
+              if (name != null) {
+                analyzeReadsInScope(name, owner, instructions, startInstruction, pyString);
+              }
+            }
+          });
+        }
+      }
+    }
+  }
+
   private void collectAllWrites(ScopeOwner owner) {
     final Instruction[] instructions = ControlFlowCache.getControlFlow(owner).getInstructions();
     for (Instruction instruction : instructions) {
@@ -180,44 +219,51 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor {
         else {
           startInstruction = i;
         }
-        // Check if the element is declared out of scope, mark all out of scope write accesses as used
-        if (element instanceof PyReferenceExpression) {
-          final PyReferenceExpression ref = (PyReferenceExpression)element;
-          final ScopeOwner declOwner = ScopeUtil.getDeclarationScopeOwner(ref, name);
-          if (declOwner != null && declOwner != owner) {
-            Collection<PsiElement> writeElements = ScopeUtil.getReadWriteElements(name, declOwner, false, true);
-            for (PsiElement e : writeElements) {
-              myUsedElements.add(e);
-              myUnusedElements.remove(e);
-            }
-          }
+        analyzeReadsInScope(name, owner, instructions, startInstruction, as(element, PyReferenceExpression.class));
+      }
+    }
+  }
+
+  private void analyzeReadsInScope(@NotNull String name, 
+                                   @NotNull ScopeOwner owner,
+                                   @NotNull Instruction[] instructions,
+                                   int startInstruction, 
+                                   @Nullable PsiElement scopeAnchor) {
+    // Check if the element is declared out of scope, mark all out of scope write accesses as used
+    if (scopeAnchor != null) {
+      final ScopeOwner declOwner = ScopeUtil.getDeclarationScopeOwner(scopeAnchor, name);
+      if (declOwner != null && declOwner != owner) {
+        final Collection<PsiElement> writeElements = ScopeUtil.getReadWriteElements(name, declOwner, false, true);
+        for (PsiElement e : writeElements) {
+          myUsedElements.add(e);
+          myUnusedElements.remove(e);
         }
-        ControlFlowUtil.iteratePrev(startInstruction, instructions, inst -> {
-          final PsiElement element1 = inst.getElement();
-          // Mark function as used
-          if (element1 instanceof PyFunction) {
-            if (name.equals(((PyFunction)element1).getName())){
-              myUsedElements.add(element1);
-              myUnusedElements.remove(element1);
-              return ControlFlowUtil.Operation.CONTINUE;
-            }
-          }
-          // Mark write access as used
-          else if (inst instanceof ReadWriteInstruction) {
-            final ReadWriteInstruction rwInstruction = (ReadWriteInstruction)inst;
-            if (rwInstruction.getAccess().isWriteAccess() && name.equals(rwInstruction.getName())) {
-              // For elements in scope
-              if (element1 != null && PsiTreeUtil.isAncestor(owner, element1, false)) {
-                myUsedElements.add(element1);
-                myUnusedElements.remove(element1);
-              }
-              return ControlFlowUtil.Operation.CONTINUE;
-            }
-          }
-          return ControlFlowUtil.Operation.NEXT;
-        });
       }
     }
+    ControlFlowUtil.iteratePrev(startInstruction, instructions, inst -> {
+      final PsiElement instElement = inst.getElement();
+      // Mark function as used
+      if (instElement instanceof PyFunction) {
+        if (name.equals(((PyFunction)instElement).getName())){
+          myUsedElements.add(instElement);
+          myUnusedElements.remove(instElement);
+          return ControlFlowUtil.Operation.CONTINUE;
+        }
+      }
+      // Mark write access as used
+      else if (inst instanceof ReadWriteInstruction) {
+        final ReadWriteInstruction rwInstruction = (ReadWriteInstruction)inst;
+        if (rwInstruction.getAccess().isWriteAccess() && name.equals(rwInstruction.getName())) {
+          // For elements in scope
+          if (instElement != null && PsiTreeUtil.isAncestor(owner, instElement, false)) {
+            myUsedElements.add(instElement);
+            myUnusedElements.remove(instElement);
+          }
+          return ControlFlowUtil.Operation.CONTINUE;
+        }
+      }
+      return ControlFlowUtil.Operation.NEXT;
+    });
   }
 
   static class DontPerformException extends RuntimeException {}
index 20ec3a9b52512d5f6a74cfe7d5a85179da702161..944f073a8e67897738ba5ac3e72f05d5ae8e358c 100644 (file)
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.StringEscapesTokenTypes;
 import com.intellij.psi.tree.IElementType;
 import com.jetbrains.python.PyTokenTypes;
+import com.jetbrains.python.PythonStringUtil;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -69,55 +70,23 @@ public class PyStringLiteralLexer extends LexerBase {
     myBufferEnd = endOffset;
 
     // the following could be parsing steps if we wanted this info as tokens
-    int i = myStart;
-
-    i = skipEncodingPrefix(buffer, i);
-    int offset = skipRawPrefix(buffer, i);
-    if (offset > i) myIsRaw = true;
-    i = offset;
-    offset = skipFormattedPrefix(buffer, i);
-    if (offset > i) myIsFormatted = true;
-    i = offset;
-    i = skipEncodingPrefix(buffer, i);
-    offset = skipRawPrefix(buffer, i);
-    if (offset > i) myIsRaw = true;
-    i = offset;
+    final String prefix = PythonStringUtil.getPrefix(buffer, myStart);
 
+    myIsFormatted = PythonStringUtil.isFormattedPrefix(prefix);
+    myIsRaw = PythonStringUtil.isRawPrefix(prefix);
+
+    final int quoteOffset = myStart + prefix.length();
     // which quote char?
-    char c = buffer.charAt(i);
+    char c = buffer.charAt(quoteOffset);
     assert (c == '"') || (c == '\'') : "String must be quoted by single or double quote. Found '" + c + "' in string " + buffer;
     myQuoteChar = c;
 
-    myIsTriple = (buffer.length() > i + 2) && (buffer.charAt(i + 1) == c) && (buffer.charAt(i + 2) == c);
+    myIsTriple = (buffer.length() > quoteOffset + 2) && (buffer.charAt(quoteOffset + 1) == c) && (buffer.charAt(quoteOffset + 2) == c);
 
     // calculate myEnd at last
     myEnd = locateToken(myStart);
   }
 
-  public static int skipFormattedPrefix(CharSequence text, int startOffset) {
-    char c = Character.toUpperCase(text.charAt(startOffset));
-    if (c == 'F') {
-      startOffset++;
-    }
-    return startOffset;
-  }
-
-  public static int skipRawPrefix(CharSequence text, int startOffset) {
-    char c = Character.toUpperCase(text.charAt(startOffset));
-    if (c == 'R') {
-      startOffset++;
-    }
-    return startOffset;
-  }
-
-  public static int skipEncodingPrefix(CharSequence text, int startOffset) {
-    char c = Character.toUpperCase(text.charAt(startOffset));
-    if (c == 'U' || c == 'B' || c == 'C') {
-      startOffset++;
-    }
-    return startOffset;
-  }
-
   public int getState() {
     return myLastState;
   }
index c7f49f080c657cc48cbbf7557257f10c0b326d87..e21a14c8b9c364841dac7e77e5adca84fb76db49 100644 (file)
@@ -46,6 +46,8 @@ IMAGNUMBER=(({FLOATNUMBER})|({INTPART}))[Jj]
 //RAW_STRING=[Rr]{QUOTED_STRING}
 //QUOTED_STRING=({TRIPLE_APOS_LITERAL})|({QUOTED_LITERAL})|({DOUBLE_QUOTED_LITERAL})|({TRIPLE_QUOTED_LITERAL})
 
+// If you change patterns for string literals, don't forget to update PythonStringUtil!
+// "c" prefix character is included for Cython
 SINGLE_QUOTED_STRING=[UuBbCcRrFf]{0,3}({QUOTED_LITERAL} | {DOUBLE_QUOTED_LITERAL})
 TRIPLE_QUOTED_STRING=[UuBbCcRrFf]{0,3}({TRIPLE_QUOTED_LITERAL}|{TRIPLE_APOS_LITERAL})
 
index c752969795a7e2b6e39508565389bca073d72c2f..cc47620fcd4923b52aa74f7c7ea387c6bb706451 100644 (file)
@@ -28,7 +28,7 @@ import com.intellij.injected.editor.VirtualFileWindow;
 import com.intellij.lang.ASTFactory;
 import com.intellij.lang.ASTNode;
 import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.application.impl.ApplicationImpl;
 import com.intellij.openapi.editor.Document;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.editor.EditorFactory;
@@ -61,12 +61,13 @@ import com.intellij.psi.stubs.StubElement;
 import com.intellij.psi.util.*;
 import com.intellij.ui.awt.RelativePoint;
 import com.intellij.util.*;
-import com.intellij.util.containers.*;
+import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.containers.HashSet;
 import com.jetbrains.NotNullPredicate;
 import com.jetbrains.python.PyBundle;
 import com.jetbrains.python.PyNames;
 import com.jetbrains.python.PyTokenTypes;
+import com.jetbrains.python.PythonStringUtil;
 import com.jetbrains.python.codeInsight.completion.OverwriteEqualsInsertHandler;
 import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
 import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
@@ -861,26 +862,31 @@ public class PyUtil {
     return result;
   }
 
+  /**
+   * This method is allowed to be called from any thread, but in general you should not set {@code modal=true} if you're calling it
+   * from the write action, because in this case {@code function} will be executed right in the current thread (presumably EDT)
+   * without any progress whatsoever to avoid possible deadlock.
+   *
+   * @see ApplicationImpl#runProcessWithProgressSynchronously(Runnable, String, boolean, Project, JComponent, String)
+   */
   public static void runWithProgress(@Nullable Project project, @Nls(capitalization = Nls.Capitalization.Title) @NotNull String title,
                                      boolean modal, boolean canBeCancelled, @NotNull final Consumer<ProgressIndicator> function) {
-    ApplicationManager.getApplication().invokeAndWait(() -> {
-      if (modal) {
-        ProgressManager.getInstance().run(new Task.Modal(project, title, canBeCancelled) {
-          @Override
-          public void run(@NotNull ProgressIndicator indicator) {
-            function.consume(indicator);
-          }
-        });
-      }
-      else {
-        ProgressManager.getInstance().run(new Task.Backgroundable(project, title, canBeCancelled) {
-          @Override
-          public void run(@NotNull ProgressIndicator indicator) {
-            function.consume(indicator);
-          }
-        });
-      }
-    }, ModalityState.current());
+    if (modal) {
+      ProgressManager.getInstance().run(new Task.Modal(project, title, canBeCancelled) {
+        @Override
+        public void run(@NotNull ProgressIndicator indicator) {
+          function.consume(indicator);
+        }
+      });
+    }
+    else {
+      ProgressManager.getInstance().run(new Task.Backgroundable(project, title, canBeCancelled) {
+        @Override
+        public void run(@NotNull ProgressIndicator indicator) {
+          function.consume(indicator);
+        }
+      });
+    }
   }
 
   /**
@@ -1964,28 +1970,28 @@ public class PyUtil {
      * @return true if given string node contains "u" or "U" prefix
      */
     public boolean isUnicode() {
-      return StringUtil.containsIgnoreCase(myPrefix, "u");
+      return PythonStringUtil.isUnicodePrefix(myPrefix);
     }
 
     /**
      * @return true if given string node contains "r" or "R" prefix
      */
     public boolean isRaw() {
-      return StringUtil.containsIgnoreCase(myPrefix, "r");
+      return PythonStringUtil.isRawPrefix(myPrefix);
     }
 
     /**
      * @return true if given string node contains "b" or "B" prefix
      */
     public boolean isBytes() {
-      return StringUtil.containsIgnoreCase(myPrefix, "b");
+      return PythonStringUtil.isBytesPrefix(myPrefix);
     }
 
     /**
      * @return true if given string node contains "f" or "F" prefix
      */
     public boolean isFormatted() {
-      return StringUtil.containsIgnoreCase(myPrefix, "f");
+      return PythonStringUtil.isFormattedPrefix(myPrefix);
     }
 
     /**
index 0bcdff58b35735b33e51f8733eaf018b65b5ee35..33306b62d56639deeab4415cc3b792e312c82cd5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2016 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,139 +18,133 @@ package com.jetbrains.python.psi.impl;
 import com.intellij.lang.ASTNode;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.tree.IElementType;
+import com.jetbrains.python.PyElementTypes;
 import com.jetbrains.python.psi.PyElementVisitor;
+import com.jetbrains.python.psi.PyNumericLiteralExpression;
+import com.jetbrains.python.psi.types.PyType;
 import com.jetbrains.python.psi.types.TypeEvalContext;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
-import com.jetbrains.python.PyElementTypes;
-import com.jetbrains.python.psi.PyNumericLiteralExpression;
-import com.jetbrains.python.psi.types.PyType;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.Optional;
 
 /**
  * @author yole
  */
-public class PyNumericLiteralExpressionImpl extends PyElementImpl
-    implements PyNumericLiteralExpression {
-  //TOLATER: imaginary numbers
-  private static final Pattern PATTERN_INT = Pattern.compile(
-      "(?:"
-          + "([1-9]\\d*)"
-          + "|(0)"
-          + "|(0[0-7]+)"
-          + "|(?:0x([0-9a-f]+))"
-          + ")L?", Pattern.CASE_INSENSITIVE);
-
-  private static final Pattern PATTERN_FLOAT = Pattern.compile(
-      "(" // 1
-          + "(\\d+)" // 2
-          + "(?:\\.(\\d+)?)?" // 3
-          + "|\\.(\\d+))" // 4
-          + "(e(\\+|-)?(\\d))?", // 5, 6, 7
-      Pattern.CASE_INSENSITIVE);
-
-    public PyNumericLiteralExpressionImpl(ASTNode astNode) {
-        super(astNode);
-    }
+public class PyNumericLiteralExpressionImpl extends PyElementImpl implements PyNumericLiteralExpression {
 
-    @Override protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
-        pyVisitor.visitPyNumericLiteralExpression(this);
-    }
+  public PyNumericLiteralExpressionImpl(@NotNull ASTNode astNode) {
+    super(astNode);
+  }
 
-    public Long getLongValue() {
-      BigInteger value = getBigIntegerValue();
-      long longValue = value.longValue();
-      if (BigInteger.valueOf(longValue).equals(value)) {
-        return longValue;
-      } else {
-        return null;
-      }
-    }
+  @Override
+  protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
+    pyVisitor.visitPyNumericLiteralExpression(this);
+  }
+
+  @Override
+  @Nullable
+  public Long getLongValue() {
+    final BigInteger value = getBigIntegerValue();
 
+    return Optional
+      .ofNullable(value)
+      .map(BigInteger::longValue)
+      .filter(longValue -> BigInteger.valueOf(longValue).equals(value))
+      .orElse(null);
+  }
+
+  @Override
+  @Nullable
   public BigInteger getBigIntegerValue() {
-    ASTNode node = getNode();
-    String text = node.getText();
-    IElementType type = node.getElementType();
-    if (type == PyElementTypes.INTEGER_LITERAL_EXPRESSION) {
-      return getBigIntegerValue(text);
-    } else {
-      return getBigDecimalValue().toBigInteger();
+    if (isIntegerLiteral()) {
+      return getBigIntegerValue(getNode().getText());
     }
+
+    final BigDecimal bigDecimal = getBigDecimalValue();
+    return bigDecimal == null ? null : bigDecimal.toBigInteger();
   }
 
+  @Override
+  @Nullable
   public BigDecimal getBigDecimalValue() {
-    ASTNode node = getNode();
-    String text = node.getText();
-    IElementType type = node.getElementType();
-    if (type == PyElementTypes.INTEGER_LITERAL_EXPRESSION) {
-      return new BigDecimal(getBigIntegerValue(text));
-    }
-    Matcher m = PATTERN_FLOAT.matcher(text);
-    boolean matches = m.matches();
-    assert matches;
-    BigDecimal whole;
-    if (m.group(2) != null) {
-      whole = new BigDecimal(m.group(2));
-      String fractionStr = m.group(3);
-      BigDecimal fraction = BigDecimal.ZERO;
-      if (fractionStr != null) {
-        fraction = new BigDecimal("0." + fractionStr);
-      }
-      whole = whole.add(fraction);
-    } else if (m.group(4) != null) {
-      whole = new BigDecimal("0." + m.group(4));
-    } else {
-      throw new IllegalStateException("Cannot parse BigDecimal for " + text);
-    }
-    if (m.group(5) != null) {
-      String sign = m.group(6);
-      if (sign == null) sign = "+";
-      String exp = m.group(7);
-      whole = whole.multiply(new BigDecimal("1e" + sign + exp));
+    final String text = getNode().getText();
+
+    if (isIntegerLiteral()) {
+      return Optional
+        .ofNullable(getBigIntegerValue(text))
+        .map(BigDecimal::new)
+        .orElse(null);
     }
-    return whole;
+
+    return new BigDecimal(prepareLiteralForJava(text, 0));
   }
 
+  @Override
   public boolean isIntegerLiteral() {
     return getNode().getElementType() == PyElementTypes.INTEGER_LITERAL_EXPRESSION;
   }
 
-  private static @Nullable BigInteger getBigIntegerValue(String text) {
-    Matcher m = PATTERN_INT.matcher(text);
-    if (!m.matches()) return null;
-    int radix;
-    if (m.group(1) != null) {
-      radix = 10;
-    } else if (m.group(2) != null) {
-      return BigInteger.ZERO;
-    } else if (m.group(3) != null) {
-      radix = 8;
-    } else if (m.group(4) != null) {
-      radix = 16;
-    } else {
-      throw new IllegalStateException("No radix found: " + text);
-    }
-    if (StringUtil.endsWithIgnoreCase(text, "L")) {
-      text = text.substring(0, text.length()-1);
-    }
-    return new BigInteger(text, radix);
-  }
-
+  @Override
+  @Nullable
   public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) {
-    ASTNode node = getNode();
-    IElementType type = node.getElementType();
-    if (type == PyElementTypes.INTEGER_LITERAL_EXPRESSION) {
+    if (isIntegerLiteral()) {
       return PyBuiltinCache.getInstance(this).getIntType();
-    } else if (type == PyElementTypes.FLOAT_LITERAL_EXPRESSION) {
+    }
+
+    final IElementType type = getNode().getElementType();
+    if (type == PyElementTypes.FLOAT_LITERAL_EXPRESSION) {
       return PyBuiltinCache.getInstance(this).getFloatType();
     }
     else if (type == PyElementTypes.IMAGINARY_LITERAL_EXPRESSION) {
       return PyBuiltinCache.getInstance(this).getComplexType();
     }
+
     return null;
   }
+
+  @Nullable
+  private static BigInteger getBigIntegerValue(@NotNull String text) {
+    if (text.equals("0") || text.equalsIgnoreCase("0l")) {
+      return BigInteger.ZERO;
+    }
+
+    final int beginIndex;
+    final int radix;
+
+    if (StringUtil.startsWithIgnoreCase(text, "0x")) {
+      beginIndex = 2;
+      radix = 16;
+    }
+    else if (StringUtil.startsWithIgnoreCase(text, "0b")) {
+      beginIndex = 2;
+      radix = 2;
+    }
+    else if (text.startsWith("0")) {
+      if (StringUtil.isChar(text, 1, 'o') || StringUtil.isChar(text, 1, 'O')) {
+        beginIndex = 2;
+        radix = 8;
+      }
+      else {
+        beginIndex = 1;
+        radix = 8;
+      }
+    }
+    else {
+      beginIndex = 0;
+      radix = 10;
+    }
+
+    return new BigInteger(prepareLiteralForJava(text, beginIndex), radix);
+  }
+
+  @NotNull
+  private static String prepareLiteralForJava(@NotNull String text, int beginIndex) {
+    final int endIndex =
+      StringUtil.endsWithIgnoreCase(text, "l") || StringUtil.endsWithIgnoreCase(text, "j") ? text.length() - 1 : text.length();
+
+    return text.substring(beginIndex, endIndex).replaceAll("_", "");
+  }
 }
index 212dadf48f467c5ae7c833468542e7f6ebb3fc23..3a13e7886567c523ee773eafa24b9cf9a638e64a 100644 (file)
@@ -28,8 +28,8 @@ import com.intellij.psi.impl.source.tree.LeafElement;
 import com.intellij.psi.tree.IElementType;