Merge remote-tracking branch 'origin/master' into amakeev/remote-debug_linux
authorAnton Makeev <Anton.Makeev@jetbrains.com>
Sat, 25 Jun 2016 11:33:38 +0000 (13:33 +0200)
committerAnton Makeev <Anton.Makeev@jetbrains.com>
Sat, 25 Jun 2016 11:33:38 +0000 (13:33 +0200)
325 files changed:
java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java
java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefineParamsDefaultValueAction.java
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DelegateWithDefaultParamValueIntentionAction.java [deleted file]
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveRedundantElseAction.java [deleted file]
java/java-impl/src/com/intellij/codeInspection/lambda/RedundantLambdaParameterTypeInspection.java [moved from java/java-impl/src/com/intellij/codeInsight/daemon/quickFix/RedundantLambdaParameterTypeIntention.java with 73% similarity]
java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyServiceImpl.java
java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/JavaStubIndexer.java
java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java
java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NamesEnumerator.java
java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java
java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java
java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyIndex.java
java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubResolver.java
java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java
java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java
java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Translator.java
java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassHandler.java
java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java
java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaUnitDescriptor.java
java/java-indexing-impl/src/com/intellij/psi/stubsHierarchy/StubHierarchyIndexer.java
java/java-psi-api/src/com/intellij/psi/util/PsiSuperMethodUtil.java
java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java
java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/hierarchy/IndexTree.java
java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/after1.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterAbstractMethod.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterCommentsInBody.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterConstructor.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterExistinMethod.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterInterface.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterJavadoc.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterReturnValue.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterStaticMethodInInterface.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterTypeParams.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterVarargs.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/before1.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeAbstractMethod.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeCommentsInBody.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeConstructor.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeExistinMethod.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeInterface.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeJavadoc.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeReturnValue.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeStaticMethodInInterface.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeTypeParams.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeVarargs.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/after1.java [deleted file]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/before1.java [deleted file]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/beforeCanThrowException.java [deleted file]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/beforeIfElseChain.java [deleted file]
java/java-tests/testData/codeInsight/multipleJdks/java7/p/I.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/multipleJdks/java7/p/UnrelatedDefaultsFromDifferentJdkVersions.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/multipleJdks/java8/p/I.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/multipleJdks/java8/p/UnrelatedDefaultsFromDifferentJdkVersions.java [new file with mode: 0644]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/Assignment.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeAssignment.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/AssignmentNoParams.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeAssignmentNoParams.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/AssignmentNoTypes.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeAssignmentNoTypes.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/Assignment_after.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/afterAssignment.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/AtVarargPlace.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeAtVarargPlace.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/CallNoTypeArgs.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeCallNoTypeArgs.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/CallNoTypeArgs1.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeCallNoTypeArgs1.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/CallWithTypeArgs.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeCallWithTypeArgs.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/CallWithTypeArgs_after.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/afterCallWithTypeArgs.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/InChain.java [new file with mode: 0644]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/InChain_after.java [new file with mode: 0644]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/InferredFromOtherArgs.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeInferredFromOtherArgs.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/InferredFromOtherArgs_after.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/afterInferredFromOtherArgs.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/NoSelfTypeParam.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeNoSelfTypeParam.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/NoSelfTypeParam_after.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/afterNoSelfTypeParam.java with 100% similarity]
java/java-tests/testData/codeInspection/redundantLambdaParameterType/TypeParam.java [moved from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeTypeParam.java with 100% similarity]
java/java-tests/testData/refactoring/extractMethod/LocalVariableAnnotationsOrder.java [new file with mode: 0644]
java/java-tests/testData/refactoring/extractMethod/LocalVariableAnnotationsOrder_after.java [new file with mode: 0644]
java/java-tests/testData/refactoring/extractMethod/LocalVariableModifierList.java [new file with mode: 0644]
java/java-tests/testData/refactoring/extractMethod/LocalVariableModifierList_after.java [new file with mode: 0644]
java/java-tests/testData/refactoring/extractMethod/MethodAnnotations.java [new file with mode: 0644]
java/java-tests/testData/refactoring/extractMethod/MethodAnnotations_after.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/codeInsight/MultipleJdksHighlightingTest.java
java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/DelegateWithDefaultParamValueTest.java
java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RedundantLambdaParameterTypeIntentionTest.java [deleted file]
java/java-tests/testSrc/com/intellij/codeInspection/RedundantLambdaParameterTypeInspectionTest.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java
java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java
platform/core-api/src/com/intellij/psi/tree/CustomParsingType.java
platform/core-api/src/com/intellij/psi/tree/ICustomParsingType.java [moved from java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RemoveRedundantElseActionTest.java with 58% similarity]
platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java
platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java
platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java
platform/diff-api/src/com/intellij/diff/comparison/ComparisonManager.java
platform/diff-api/src/com/intellij/diff/fragments/MergeLineFragment.java [moved from platform/diff-impl/src/com/intellij/diff/fragments/MergeLineFragment.java with 100% similarity]
platform/diff-api/src/com/intellij/diff/fragments/MergeWordFragment.java [moved from platform/diff-impl/src/com/intellij/diff/fragments/MergeWordFragment.java with 100% similarity]
platform/diff-impl/src/com/intellij/diff/comparison/ByLine.java
platform/diff-impl/src/com/intellij/diff/comparison/ByWord.java
platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java
platform/diff-impl/src/com/intellij/diff/comparison/TextChunk.java [deleted file]
platform/diff-impl/src/com/intellij/diff/comparison/iterables/DiffIterableUtil.java
platform/diff-impl/src/com/intellij/diff/fragments/MergeLineFragmentImpl.java
platform/diff-impl/src/com/intellij/diff/fragments/MergeWordFragmentImpl.java
platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java
platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java
platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt
platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt
platform/icons/src/icon.png
platform/icons/src/windows/close.png [deleted file]
platform/icons/src/windows/closeActive.png [new file with mode: 0644]
platform/icons/src/windows/closeActive@2x.png [new file with mode: 0644]
platform/icons/src/windows/closeActive@2x_dark.png [new file with mode: 0644]
platform/icons/src/windows/closeActive_dark.png [new file with mode: 0644]
platform/icons/src/windows/closeHover.png [new file with mode: 0644]
platform/icons/src/windows/closeHover@2x.png [new file with mode: 0644]
platform/icons/src/windows/closeInactive.png [new file with mode: 0644]
platform/icons/src/windows/closeInactive@2x.png [new file with mode: 0644]
platform/icons/src/windows/closeInactive@2x_dark.png [new file with mode: 0644]
platform/icons/src/windows/closeInactive_dark.png [new file with mode: 0644]
platform/icons/src/windows/iconify.png [deleted file]
platform/icons/src/windows/maximize.png [deleted file]
platform/icons/src/windows/maximize@2x.png [new file with mode: 0644]
platform/icons/src/windows/maximize@2x_dark.png [new file with mode: 0644]
platform/icons/src/windows/maximizeInactive.png [new file with mode: 0644]
platform/icons/src/windows/maximizeInactive@2x.png [new file with mode: 0644]
platform/icons/src/windows/maximizeInactive@2x_dark.png [new file with mode: 0644]
platform/icons/src/windows/maximizeInactive_dark.png [new file with mode: 0644]
platform/icons/src/windows/maximize_dark.png [new file with mode: 0644]
platform/icons/src/windows/minimize.png
platform/icons/src/windows/minimize@2x.png [new file with mode: 0644]
platform/icons/src/windows/minimize@2x_dark.png [new file with mode: 0644]
platform/icons/src/windows/minimizeInactive.png [new file with mode: 0644]
platform/icons/src/windows/minimizeInactive@2x.png [new file with mode: 0644]
platform/icons/src/windows/minimizeInactive@2x_dark.png [new file with mode: 0644]
platform/icons/src/windows/minimizeInactive_dark.png [new file with mode: 0644]
platform/icons/src/windows/minimize_dark.png [new file with mode: 0644]
platform/icons/src/windows/restore.png [new file with mode: 0644]
platform/icons/src/windows/restore@2x.png [new file with mode: 0644]
platform/icons/src/windows/restore@2x_dark.png [new file with mode: 0644]
platform/icons/src/windows/restoreInactive.png [new file with mode: 0644]
platform/icons/src/windows/restoreInactive@2x.png [new file with mode: 0644]
platform/icons/src/windows/restoreInactive@2x_dark.png [new file with mode: 0644]
platform/icons/src/windows/restoreInactive_dark.png [new file with mode: 0644]
platform/icons/src/windows/restore_dark.png [new file with mode: 0644]
platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java
platform/lang-api/src/com/intellij/codeInsight/completion/OffsetMap.java
platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
platform/lang-impl/src/com/intellij/codeInsight/completion/ComboEditorCompletionContributor.java
platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java
platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java
platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java
platform/lang-impl/src/com/intellij/codeInspection/ex/SeverityEditorDialog.java
platform/lang-impl/src/com/intellij/formatting/FormatterTagHandler.java
platform/lang-impl/src/com/intellij/ide/scopeView/ScopePaneSelectInTarget.java
platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java
platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java
platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java
platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java
platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java
platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java
platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java
platform/platform-api/src/com/intellij/openapi/fileEditor/TextEditorLocation.java
platform/platform-api/src/com/intellij/openapi/wm/ToolWindow.java
platform/platform-api/src/com/intellij/openapi/wm/ToolWindowAnchor.java
platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java
platform/platform-impl/src/com/intellij/designer/LightToolWindow.java
platform/platform-impl/src/com/intellij/ide/actions/SaveDocumentAction.java
platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula_windows.properties
platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTitlePane.java
platform/platform-impl/src/com/intellij/openapi/project/FileContentQueue.java
platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java
platform/platform-impl/src/com/intellij/openapi/wm/ex/DefaultFrameEditorComponentProvider.java
platform/platform-impl/src/com/intellij/openapi/wm/ex/FrameEditorComponentProvider.java
platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/ActiveStack.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/DesktopLayout.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecoratorListener.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/Stripe.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowInfoImpl.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowedDecorator.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/commands/FinalizableCommand.java
platform/platform-resources/src/brokenPlugins.txt
platform/testFramework/src/com/intellij/mock/Mock.java
platform/usageView/src/com/intellij/usages/UsageViewPresentation.java
platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java
platform/util/src/com/intellij/icons/AllIcons.java
platform/util/src/com/intellij/util/RetinaImage.java
platform/util/src/com/intellij/util/concurrency/SchedulingWrapper.java
platform/util/src/com/intellij/util/diff/Diff.java
platform/util/src/com/intellij/util/ui/UIUtil.java
platform/vcs-impl/src/com/intellij/diff/Block.java
platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.form [deleted file]
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.java
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/NewEditChangelistPanel.java
platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java
platform/vcs-impl/src/com/intellij/openapi/vcs/history/impl/VcsSelectionHistoryDialog.java
platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java
platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsInitialization.java
platform/vcs-log/impl/src/com/intellij/vcs/log/statistics/VcsLogRepoSizeCollector.java
plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java
plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/IfStatementWithIdenticalBranches.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrTraitMethod.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/hierarchy/GrStubIndexer.java
plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/Gr23HighlightingTest.groovy
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditAnswerPlaceholder.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskMoveHandlerDelegate.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderPanel.form
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderPanel.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateStudyItemPanel.java
python/educational-core/student/resources/META-INF/plugin.xml
python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java
python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java
python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java
python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java
python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyNextWindowAction.java
python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java
python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java
python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java
python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java
python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java
python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java
python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java
python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java
python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyGenerator.java
python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyDirectoryNode.java
python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyConfigurable.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/CourseInfo.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicNames.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicAdaptiveReactionsPanel.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicStudyOptions.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java
python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterUtils.java
python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyProgressBar.java
python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyProgressToolWindowFactory.java [deleted file]
python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java
python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java
python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationProducer.java
python/educational-python/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java
python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java
python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyInstructionPainter.java
python/helpers/pycharm/tcunittest.py
python/helpers/pycharm_generator_utils/module_redeclarator.py
python/helpers/pydev/_pydev_bundle/pydev_console_utils.py
python/helpers/pydev/_pydevd_bundle/pydevd_comm.py
python/helpers/pydev/pydevd.py
python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java
python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificSettingsStep.java
python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java
python/ipnb/src/org/jetbrains/plugins/ipnb/format/IpnbParser.java
python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java
python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java
python/openapi/src/com/jetbrains/python/templateLanguages/PyTemplatesUtil.java [deleted file]
python/openapi/src/com/jetbrains/python/templateLanguages/PythonTemplateIndentOptionsProvider.java [deleted file]
python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java
python/pluginJava/com/jetbrains/python/psi/impl/PyJavaImportCandidateProvider.java
python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java
python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java
python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java
python/python-community-configure/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java
python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
python/python-rest/src/com/jetbrains/rest/run/sphinx/SphinxRunConfiguration.java
python/src/com/jetbrains/python/PyBundle.properties
python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java
python/src/com/jetbrains/python/console/PythonConsoleView.java
python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java
python/src/com/jetbrains/python/debugger/PyDebugProcess.java
python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java
python/src/com/jetbrains/python/packaging/PyCondaPackageManagerImpl.java
python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java
python/src/com/jetbrains/python/packaging/PyPackageUtil.java
python/src/com/jetbrains/python/packaging/PyRemotePackageManagerImpl.java
python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java
python/src/com/jetbrains/python/packaging/ui/PyPackageManagementService.java
python/src/com/jetbrains/python/psi/PyUtil.java
python/src/com/jetbrains/python/sdk/PythonSdkType.java
python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java
python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
python/src/com/jetbrains/python/testing/PyIntegratedToolsProjectConfigurator.java
python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java
python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java
python/testSrc/com/jetbrains/env/PyEnvTestCase.java
python/testSrc/com/jetbrains/env/python/PyPackagingTest.java
python/testSrc/com/jetbrains/python/inspections/PyPackageRequirementsInspectionTest.java
resources-en/src/inspectionDescriptions/RedundantLambdaParameterType.html [new file with mode: 0644]
resources-en/src/intentionDescriptions/DelegateWithDefaultParamValueIntentionAction/after.java.template [deleted file]
resources-en/src/intentionDescriptions/DelegateWithDefaultParamValueIntentionAction/before.java.template [deleted file]
resources-en/src/intentionDescriptions/DelegateWithDefaultParamValueIntentionAction/description.html [deleted file]
resources-en/src/intentionDescriptions/RedundantLambdaParameterTypeIntention/after.java.template [deleted file]
resources-en/src/intentionDescriptions/RedundantLambdaParameterTypeIntention/before.java.template [deleted file]
resources-en/src/intentionDescriptions/RedundantLambdaParameterTypeIntention/description.html [deleted file]
resources-en/src/intentionDescriptions/RemoveRedundantElseAction/after.java.template [deleted file]
resources-en/src/intentionDescriptions/RemoveRedundantElseAction/before.java.template [deleted file]
resources-en/src/intentionDescriptions/RemoveRedundantElseAction/description.html [deleted file]
resources/src/META-INF/IdeaPlugin.xml
xml/relaxng/src/resources/html5-schema/html5/block.rnc
xml/relaxng/src/resources/html5-schema/html5/common.rnc
xml/relaxng/src/resources/html5-schema/html5/data.rnc
xml/relaxng/src/resources/html5-schema/html5/embed.rnc
xml/relaxng/src/resources/html5-schema/html5/html5.rnc
xml/relaxng/src/resources/html5-schema/html5/meta.rnc
xml/relaxng/src/resources/html5-schema/html5/phrase.rnc
xml/relaxng/src/resources/html5-schema/html5/structural.rnc
xml/relaxng/src/resources/html5-schema/html5/web-forms.rnc
xml/relaxng/src/resources/html5-schema/html5/web-forms2.rnc
xml/relaxng/src/resources/html5-schema/html5/xhtml5.rnc
xml/relaxng/src/resources/html5-schema/html5chars.ent
xml/relaxng/src/resources/html5-schema/svg11/svg-script.rnc
xml/relaxng/src/resources/html5charref.rb
xml/relaxng/src/resources/patches/0004_ping.patch
xml/xml-psi-impl/src/com/intellij/psi/xml/XmlElementType.java

index 1da4eb7fd6b82101154f010471c1dcd396a303eb..2a7b7963145b647dde01d0b51cb067219295f56e 100644 (file)
@@ -30,6 +30,7 @@ import com.intellij.refactoring.extractMethod.InputVariables;
 import com.intellij.refactoring.util.RefactoringChangeUtil;
 import com.intellij.util.ArrayUtil;
 import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.containers.IntArrayList;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -518,6 +519,8 @@ public class DuplicatesFinder {
         final PsiJavaCodeReferenceElement candidateQualifier = ((PsiSuperExpression)candidate).getQualifier();
         return contextClass == (candidateQualifier != null ? candidateQualifier.resolve() : PsiTreeUtil.getContextOfType(candidate, PsiClass.class));
       }
+    } else if (pattern instanceof PsiModifierList) {
+      return candidate instanceof PsiModifierList && matchModifierList((PsiModifierList)pattern, (PsiModifierList)candidate);
     }
 
     PsiElement[] children1 = getFilteredChildren(pattern);
@@ -541,6 +544,40 @@ public class DuplicatesFinder {
     return true;
   }
 
+  private static boolean matchModifierList(PsiModifierList modifierList1, PsiModifierList modifierList2) {
+    if (!(modifierList1.getParent() instanceof PsiLocalVariable)) {
+      // local variables can only have a final modifier, and are considered equivalent with or without it.
+      for (String modifier : PsiModifier.MODIFIERS) {
+        if (modifierList1.hasModifierProperty(modifier)) {
+          if (!modifierList2.hasModifierProperty(modifier)) {
+            return false;
+          }
+        }
+        else if (modifierList2.hasModifierProperty(modifier)) {
+          return false;
+        }
+      }
+    }
+    final List<PsiAnnotation> annotations1 = ContainerUtil.newArrayList(modifierList1.getAnnotations());
+    final List<PsiAnnotation> annotations2 = ContainerUtil.newArrayList(modifierList2.getAnnotations());
+    annotations1.removeIf(a -> CommonClassNames.JAVA_LANG_OVERRIDE.equals(a.getQualifiedName()));
+    annotations2.removeIf(a -> CommonClassNames.JAVA_LANG_OVERRIDE.equals(a.getQualifiedName()));
+    if (annotations1.size() != annotations2.size()) {
+      return false;
+    }
+    for (final Iterator<PsiAnnotation> iterator = annotations1.iterator(); iterator.hasNext(); ) {
+      final PsiAnnotation annotation1 = iterator.next();
+      for (final Iterator<PsiAnnotation> iterator2 = annotations2.iterator(); iterator2.hasNext(); ) {
+        final PsiAnnotation annotation2 = iterator2.next();
+        if (PsiEquivalenceUtil.areElementsEquivalent(annotation1, annotation2)) {
+          iterator.remove();
+          iterator2.remove();
+        }
+      }
+    }
+    return true;
+  }
+
   private static boolean checkParameterModification(PsiExpression expression,
                                                     final IElementType sign,
                                                     PsiExpression candidate) {
index 88d14aa13d776777ff117deb55f4dd81de75c533..c2ce494ab9577cb21626adc9a32471758ace27c9 100644 (file)
@@ -58,7 +58,7 @@ public class ConstructorInsertHandler implements InsertHandler<LookupElementDeco
 
     boolean isAbstract = psiClass.hasModifierProperty(PsiModifier.ABSTRACT);
 
-    if (Lookup.REPLACE_SELECT_CHAR == context.getCompletionChar()) {
+    if (Lookup.REPLACE_SELECT_CHAR == context.getCompletionChar() && context.getOffsetMap().containsOffset(PARAM_LIST_START)) {
       final int plStart = context.getOffset(PARAM_LIST_START);
       final int plEnd = context.getOffset(PARAM_LIST_END);
       if (plStart >= 0 && plEnd >= 0) {
index 7440f6feb0e844241031d66824ab0a23d366646f..8374967361d3d3edba504fe99d7e2b7f6e665870 100644 (file)
  */
 package com.intellij.codeInsight.daemon.impl.quickfix;
 
+import com.intellij.codeInsight.FileModificationService;
+import com.intellij.codeInsight.generation.ClassMember;
+import com.intellij.codeInsight.hint.HintManager;
+import com.intellij.codeInsight.intention.LowPriorityAction;
+import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
 import com.intellij.codeInsight.intention.impl.ParameterClassMember;
+import com.intellij.codeInsight.template.Template;
+import com.intellij.codeInsight.template.TemplateBuilderImpl;
+import com.intellij.codeInsight.template.impl.TextExpression;
+import com.intellij.icons.AllIcons;
 import com.intellij.ide.util.MemberChooser;
 import com.intellij.lang.java.JavaLanguage;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.RangeMarker;
 import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Iconable;
+import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.CodeStyleManager;
 import com.intellij.psi.util.PsiTreeUtil;
 import com.intellij.psi.util.PsiUtil;
+import com.intellij.refactoring.util.RefactoringUtil;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.IncorrectOperationException;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import javax.swing.*;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 
 /**
  * User: anna
  * Date: 8/2/12
  */
-public class DefineParamsDefaultValueAction extends DelegateWithDefaultParamValueIntentionAction {
+public class DefineParamsDefaultValueAction extends PsiElementBaseIntentionAction implements Iconable, LowPriorityAction {
+  private static final Logger LOG = Logger.getInstance(DefineParamsDefaultValueAction.class);
+
+  @Override
+  public boolean startInWriteAction() {
+    return false;
+  }
+
+  @NotNull
+  @Override
+  public String getFamilyName() {
+    return "Generate overloaded method with default parameter values";
+  }
+
+  @Override
+  public Icon getIcon(int flags) {
+    return AllIcons.Actions.RefactoringBulb;
+  }
 
   @Override
   public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
@@ -56,20 +94,106 @@ public class DefineParamsDefaultValueAction extends DelegateWithDefaultParamValu
     return true;
   }
 
-  @Nullable
   @Override
+  public void invoke(@NotNull final Project project, final Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
+    final PsiParameter[] parameters = getParams(element);
+    if (parameters == null || parameters.length == 0) return;
+    final PsiMethod method = (PsiMethod)parameters[0].getDeclarationScope();
+    final PsiMethod methodPrototype = generateMethodPrototype(method, parameters);
+    final PsiClass containingClass = method.getContainingClass();
+    if (containingClass == null) return;
+    final PsiMethod existingMethod = containingClass.findMethodBySignature(methodPrototype, false);
+    if (existingMethod != null) {
+      editor.getCaretModel().moveToOffset(existingMethod.getTextOffset());
+      HintManager.getInstance().showErrorHint(editor, (existingMethod.isConstructor() ? "Constructor" : "Method") +
+                                                      " with the chosen signature already exists");
+      return;
+    }
+
+    if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
+
+    Runnable runnable = () -> {
+      final PsiMethod prototype = (PsiMethod)containingClass.addBefore(methodPrototype, method);
+      RefactoringUtil.fixJavadocsForParams(prototype, new HashSet<PsiParameter>(Arrays.asList(prototype.getParameterList().getParameters())));
+      TemplateBuilderImpl builder = new TemplateBuilderImpl(prototype);
+
+      PsiCodeBlock body = prototype.getBody();
+      final String callArgs =
+        "(" + StringUtil.join(method.getParameterList().getParameters(), psiParameter -> {
+          if (ArrayUtil.find(parameters, psiParameter) > -1) return "IntelliJIDEARulezzz";
+          return psiParameter.getName();
+        }, ",") + ");";
+      final String methodCall;
+      if (method.getReturnType() == null) {
+        methodCall = "this";
+      } else if (!PsiType.VOID.equals(method.getReturnType())) {
+        methodCall = "return " + method.getName();
+      } else {
+        methodCall = method.getName();
+      }
+      LOG.assertTrue(body != null);
+      body.add(JavaPsiFacade.getElementFactory(project).createStatementFromText(methodCall + callArgs, method));
+      body = (PsiCodeBlock)CodeStyleManager.getInstance(project).reformat(body);
+      final PsiStatement stmt = body.getStatements()[0];
+      PsiExpression expr = null;
+      if (stmt instanceof PsiReturnStatement) {
+        expr = ((PsiReturnStatement)stmt).getReturnValue();
+      } else if (stmt instanceof PsiExpressionStatement) {
+        expr = ((PsiExpressionStatement)stmt).getExpression();
+      }
+      if (expr instanceof PsiMethodCallExpression) {
+        PsiMethodCallExpression methodCallExp = (PsiMethodCallExpression)expr;
+        RangeMarker rangeMarker = editor.getDocument().createRangeMarker(prototype.getTextRange());
+        for (PsiParameter parameter : parameters) {
+          final PsiExpression exprToBeDefault =
+            methodCallExp.getArgumentList().getExpressions()[method.getParameterList().getParameterIndex(parameter)];
+          builder.replaceElement(exprToBeDefault, new TextExpression(""));
+        }
+        Template template = builder.buildTemplate();
+        editor.getCaretModel().moveToOffset(rangeMarker.getStartOffset());
+
+        PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument());
+        editor.getDocument().deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset());
+
+        rangeMarker.dispose();
+
+        CreateFromUsageBaseFix.startTemplate(editor, template, project);
+      }
+    };
+    if (startInWriteAction()) {
+      runnable.run();
+    } else {
+      ApplicationManager.getApplication().runWriteAction(runnable);
+    }
+  }
+
+  @Nullable
   protected PsiParameter[] getParams(PsiElement element) {
     final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class);
     assert method != null;
     final PsiParameter[] parameters = method.getParameterList().getParameters();
+    if (parameters.length == 1) {
+      return parameters;
+    }
     final ParameterClassMember[] members = new ParameterClassMember[parameters.length];
     for (int i = 0; i < members.length; i++) {
       members[i] = new ParameterClassMember(parameters[i]);
     }
+    final PsiParameter selectedParam = PsiTreeUtil.getParentOfType(element, PsiParameter.class);
+    final int idx = selectedParam != null ? ArrayUtil.find(parameters, selectedParam) : -1;
+    if (ApplicationManager.getApplication().isUnitTestMode()) {
+      return idx >= 0 ? new PsiParameter[] {selectedParam} : null;
+    }
     final MemberChooser<ParameterClassMember> chooser =
       new MemberChooser<ParameterClassMember>(members, false, true, element.getProject());
-    chooser.selectElements(members);
+    if (idx >= 0) {
+      chooser.selectElements(new ClassMember[] {members[idx]});
+    }
+    else {
+      chooser.selectElements(members);
+    }
     chooser.setTitle("Choose Default Value Parameters");
+    chooser.setCopyJavadocVisible(false);
     if (chooser.showAndGet()) {
       final List<ParameterClassMember> elements = chooser.getSelectedElements();
       if (elements != null) {
@@ -83,14 +207,34 @@ public class DefineParamsDefaultValueAction extends DelegateWithDefaultParamValu
     return null;
   }
 
-  @Override
-  public boolean startInWriteAction() {
-    return false;
-  }
+  private static PsiMethod generateMethodPrototype(PsiMethod method, PsiParameter... params) {
+    final PsiMethod prototype = (PsiMethod)method.copy();
+    final PsiCodeBlock body = prototype.getBody();
+    final PsiCodeBlock emptyBody = JavaPsiFacade.getElementFactory(method.getProject()).createMethodFromText("void foo(){}", prototype).getBody();
+    assert emptyBody != null;
+    if (body != null) {
+      body.replace(emptyBody);
+    } else {
+      prototype.getModifierList().setModifierProperty(PsiModifier.ABSTRACT, false);
+      prototype.addBefore(emptyBody, null);
+    }
 
-  @NotNull
-  @Override
-  public String getFamilyName() {
-    return "Generate overloaded method with default parameter values";
+    final PsiClass aClass = method.getContainingClass();
+    if (aClass != null && aClass.isInterface() && !method.hasModifierProperty(PsiModifier.STATIC)) {
+      prototype.getModifierList().setModifierProperty(PsiModifier.DEFAULT, true);
+    }
+
+    final PsiParameterList parameterList = method.getParameterList();
+    Arrays.sort(params, (p1, p2) -> {
+      final int parameterIndex1 = parameterList.getParameterIndex(p1);
+      final int parameterIndex2 = parameterList.getParameterIndex(p2);
+      return parameterIndex1 > parameterIndex2 ? -1 : 1;
+    });
+
+    for (PsiParameter param : params) {
+      final int parameterIndex = parameterList.getParameterIndex(param);
+      prototype.getParameterList().getParameters()[parameterIndex].delete();
+    }
+    return prototype;
   }
 }
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DelegateWithDefaultParamValueIntentionAction.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DelegateWithDefaultParamValueIntentionAction.java
deleted file mode 100644 (file)
index d3bbc2b..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright 2000-2015 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.codeInsight.daemon.impl.quickfix;
-
-import com.intellij.codeInsight.FileModificationService;
-import com.intellij.codeInsight.hint.HintManager;
-import com.intellij.codeInsight.intention.LowPriorityAction;
-import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
-import com.intellij.codeInsight.template.Template;
-import com.intellij.codeInsight.template.TemplateBuilderImpl;
-import com.intellij.codeInsight.template.impl.TextExpression;
-import com.intellij.icons.AllIcons;
-import com.intellij.lang.StdLanguages;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.RangeMarker;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Iconable;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.*;
-import com.intellij.psi.codeStyle.CodeStyleManager;
-import com.intellij.psi.util.PsiTreeUtil;
-import com.intellij.psi.util.PsiUtil;
-import com.intellij.refactoring.util.RefactoringUtil;
-import com.intellij.util.ArrayUtil;
-import com.intellij.util.Function;
-import com.intellij.util.IncorrectOperationException;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashSet;
-
-/**
- * User: anna
- */
-public class DelegateWithDefaultParamValueIntentionAction extends PsiElementBaseIntentionAction implements Iconable, LowPriorityAction {
-  @Override
-  public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
-    final PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class);
-    if (parameter != null) {
-      if (!parameter.getLanguage().isKindOf(StdLanguages.JAVA)) return false;
-      final PsiElement declarationScope = parameter.getDeclarationScope();
-      if (declarationScope instanceof PsiMethod) {
-        final PsiMethod method = (PsiMethod)declarationScope;
-        final PsiClass containingClass = method.getContainingClass();
-        if (containingClass != null && (!containingClass.isInterface() || PsiUtil.isLanguageLevel8OrHigher(method))) {
-          if (containingClass.findMethodBySignature(generateMethodPrototype(method, parameter), false) != null) {
-            return false;
-          }
-          setText("Generate overloaded " + (method.isConstructor() ? "constructor" : "method") + " with default parameter value");
-          return true;
-        }
-      }
-    }
-    return false;
-  }
-
-  @Override
-  public Icon getIcon(int flags) {
-    return AllIcons.Actions.RefactoringBulb;
-  }
-
-  private static PsiMethod generateMethodPrototype(PsiMethod method, PsiParameter... params) {
-    final PsiMethod prototype = (PsiMethod)method.copy();
-    final PsiCodeBlock body = prototype.getBody();
-    final PsiCodeBlock emptyBody = JavaPsiFacade.getElementFactory(method.getProject()).createMethodFromText("void foo(){}", prototype).getBody();
-    assert emptyBody != null;
-    if (body != null) {
-      body.replace(emptyBody);
-    } else {
-      prototype.getModifierList().setModifierProperty(PsiModifier.ABSTRACT, false);
-      prototype.addBefore(emptyBody, null);
-    }
-
-    final PsiClass aClass = method.getContainingClass();
-    if (aClass != null && aClass.isInterface() && !method.hasModifierProperty(PsiModifier.STATIC)) {
-      prototype.getModifierList().setModifierProperty(PsiModifier.DEFAULT, true);
-    }
-
-    final PsiParameterList parameterList = method.getParameterList();
-    Arrays.sort(params, (p1, p2) -> {
-      final int parameterIndex1 = parameterList.getParameterIndex(p1);
-      final int parameterIndex2 = parameterList.getParameterIndex(p2);
-      return parameterIndex1 > parameterIndex2 ? -1 : 1;
-    });
-
-    for (PsiParameter param : params) {
-      final int parameterIndex = parameterList.getParameterIndex(param);
-      prototype.getParameterList().getParameters()[parameterIndex].delete();
-    }
-    return prototype;
-  }
-
-  @Override
-  public void invoke(@NotNull final Project project, final Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
-    final PsiParameter[] parameters = getParams(element);
-    if (parameters == null || parameters.length == 0) return;
-    final PsiMethod method = (PsiMethod)parameters[0].getDeclarationScope();
-    final PsiMethod methodPrototype = generateMethodPrototype(method, parameters);
-    final PsiMethod existingMethod = method.getContainingClass().findMethodBySignature(methodPrototype, false);
-    if (existingMethod != null) {
-      editor.getCaretModel().moveToOffset(existingMethod.getTextOffset());
-      HintManager.getInstance().showErrorHint(editor, (existingMethod.isConstructor() ? "Constructor" : "Method") +
-                                                      " with the chosen signature already exists");
-      return;
-    }
-
-    if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
-    
-    Runnable runnable = () -> {
-
-      final PsiMethod prototype = (PsiMethod)method.getContainingClass().addBefore(methodPrototype, method);
-      RefactoringUtil.fixJavadocsForParams(prototype, new HashSet<PsiParameter>(Arrays.asList(prototype.getParameterList().getParameters())));
-      TemplateBuilderImpl builder = new TemplateBuilderImpl(prototype);
-
-      PsiCodeBlock body = prototype.getBody();
-      final String callArgs =
-        "(" + StringUtil.join(method.getParameterList().getParameters(), psiParameter -> {
-          if (ArrayUtil.find(parameters, psiParameter) > -1) return "IntelliJIDEARulezzz";
-          return psiParameter.getName();
-        }, ",") + ");";
-      final String methodCall;
-      if (method.getReturnType() == null) {
-        methodCall = "this";
-      } else if (!PsiType.VOID.equals(method.getReturnType())) {
-        methodCall = "return " + method.getName();
-      } else {
-        methodCall = method.getName();
-      }
-      body.add(JavaPsiFacade.getElementFactory(project).createStatementFromText(methodCall + callArgs, method));
-      body = (PsiCodeBlock)CodeStyleManager.getInstance(project).reformat(body);
-      final PsiStatement stmt = body.getStatements()[0];
-      PsiExpression expr = null;
-      if (stmt instanceof PsiReturnStatement) {
-        expr = ((PsiReturnStatement)stmt).getReturnValue();
-      } else if (stmt instanceof PsiExpressionStatement) {
-        expr = ((PsiExpressionStatement)stmt).getExpression();
-      }
-      if (expr instanceof PsiMethodCallExpression) {
-        PsiMethodCallExpression methodCallExp = (PsiMethodCallExpression)expr;
-        RangeMarker rangeMarker = editor.getDocument().createRangeMarker(prototype.getTextRange());
-        for (PsiParameter parameter : parameters) {
-          final PsiExpression exprToBeDefault =
-            methodCallExp.getArgumentList().getExpressions()[method.getParameterList().getParameterIndex(parameter)];
-          builder.replaceElement(exprToBeDefault, new TextExpression(""));
-        }
-        Template template = builder.buildTemplate();
-        editor.getCaretModel().moveToOffset(rangeMarker.getStartOffset());
-
-        PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument());
-        editor.getDocument().deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset());
-
-        rangeMarker.dispose();
-
-        CreateFromUsageBaseFix.startTemplate(editor, template, project);
-      }
-    };
-    if (startInWriteAction()) {
-      runnable.run();
-    } else {
-      ApplicationManager.getApplication().runWriteAction(runnable);
-    }
-  }
-
-  @Nullable
-  protected PsiParameter[] getParams(PsiElement element) {
-    return new PsiParameter[]{PsiTreeUtil.getParentOfType(element, PsiParameter.class)};
-  }
-
-  @NotNull
-  @Override
-  public String getFamilyName() {
-    return "Generate overloaded method with default parameter value";
-  }
-}
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveRedundantElseAction.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveRedundantElseAction.java
deleted file mode 100644 (file)
index 28db235..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2000-2009 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.codeInsight.daemon.impl.quickfix;
-
-import com.intellij.codeInsight.FileModificationService;
-import com.intellij.codeInsight.daemon.QuickFixBundle;
-import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.*;
-import com.intellij.psi.controlFlow.*;
-import com.intellij.psi.util.PsiTreeUtil;
-import com.intellij.util.BitUtil;
-import com.intellij.util.IncorrectOperationException;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * @author ven
- */
-public class RemoveRedundantElseAction extends PsiElementBaseIntentionAction {
-  private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.RemoveRedundantElseAction");
-
-  @Override
-  @NotNull
-  public String getText() {
-    return QuickFixBundle.message("remove.redundant.else.fix");
-  }
-
-  @Override
-  @NotNull
-  public String getFamilyName() {
-    return QuickFixBundle.message("remove.redundant.else.fix");
-  }
-
-  @Override
-  public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
-    if (element instanceof PsiKeyword &&
-        element.getParent() instanceof PsiIfStatement &&
-        PsiKeyword.ELSE.equals(element.getText())) {
-      PsiIfStatement ifStatement = (PsiIfStatement)element.getParent();
-      if (ifStatement.getElseBranch() == null) return false;
-      PsiStatement thenBranch = ifStatement.getThenBranch();
-      if (thenBranch == null) return false;
-      PsiElement block = PsiTreeUtil.getParentOfType(ifStatement, PsiCodeBlock.class);
-      if (block != null) {
-        while (cantCompleteNormally(thenBranch, block)) {
-          thenBranch = getPrevThenBranch(thenBranch);
-          if (thenBranch == null) return true;
-        }
-        return false;
-      }
-    }
-    return false;
-  }
-
-  @Nullable
-  private static PsiStatement getPrevThenBranch(@NotNull PsiElement thenBranch) {
-    final PsiElement ifStatement = thenBranch.getParent();
-    final PsiElement parent = ifStatement.getParent();
-    if (parent instanceof PsiIfStatement && ((PsiIfStatement)parent).getElseBranch() == ifStatement) {
-      return ((PsiIfStatement)parent).getThenBranch();
-    }
-    return null;
-  }
-
-  private static boolean cantCompleteNormally(@NotNull PsiStatement thenBranch, PsiElement block) {
-    try {
-      ControlFlow controlFlow = ControlFlowFactory.getInstance(thenBranch.getProject()).getControlFlow(block, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance());
-      int startOffset = controlFlow.getStartOffset(thenBranch);
-      int endOffset = controlFlow.getEndOffset(thenBranch);
-      return startOffset != -1 && endOffset != -1 && !BitUtil.isSet(ControlFlowUtil.getCompletionReasons(controlFlow, startOffset, endOffset), ControlFlowUtil.NORMAL_COMPLETION_REASON);
-    }
-    catch (AnalysisCanceledException e) {
-      return false;
-    }
-  }
-
-  @Override
-  public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
-    if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
-    PsiIfStatement ifStatement = (PsiIfStatement)element.getParent();
-    LOG.assertTrue(ifStatement != null && ifStatement.getElseBranch() != null);
-    PsiStatement elseBranch = ifStatement.getElseBranch();
-    if (elseBranch instanceof PsiBlockStatement) {
-      PsiElement[] statements = ((PsiBlockStatement)elseBranch).getCodeBlock().getStatements();
-      if (statements.length > 0) {
-        ifStatement.getParent().addRangeAfter(statements[0], statements[statements.length-1], ifStatement);
-      }
-    } else {
-      ifStatement.getParent().addAfter(elseBranch, ifStatement);
-    }
-    ifStatement.getElseBranch().delete();
-  }
-}
similarity index 73%
rename from java/java-impl/src/com/intellij/codeInsight/daemon/quickFix/RedundantLambdaParameterTypeIntention.java
rename to java/java-impl/src/com/intellij/codeInspection/lambda/RedundantLambdaParameterTypeInspection.java
index 38eacc30395ab2390c1edbf1760cffb32feb72a5..4e2445fbaee99b58e5cd95cf9c4a83fd06a39dae 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2016 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.daemon.quickFix;
+package com.intellij.codeInspection.lambda;
 
-import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
+import com.intellij.codeInspection.BaseJavaBatchLocalInspectionTool;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.codeInspection.ProblemsHolder;
 import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.*;
 import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
 import com.intellij.psi.infos.MethodCandidateInfo;
-import com.intellij.psi.util.PsiTreeUtil;
 import com.intellij.psi.util.PsiUtil;
-import com.intellij.util.Function;
-import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.Nls;
 import org.jetbrains.annotations.NotNull;
 
 /**
  * User: anna
  */
-public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntentionAction {
-  public static final Logger LOG = Logger.getInstance("#" + RedundantLambdaParameterTypeIntention.class.getName());
+public class RedundantLambdaParameterTypeInspection extends BaseJavaBatchLocalInspectionTool {
+  public static final Logger LOG = Logger.getInstance("#" + RedundantLambdaParameterTypeInspection.class.getName());
 
   @NotNull
   @Override
-  public String getFamilyName() {
-    return "Remove redundant types";
-  }
-
-  @NotNull
-  @Override
-  public String getText() {
-    return getFamilyName();
+  public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
+    return new JavaElementVisitor() {
+      @Override
+      public void visitParameterList(PsiParameterList parameterList) {
+        super.visitParameterList(parameterList);
+        if (isApplicable(parameterList)) {
+          holder.registerProblem(parameterList, "Remove redundant types", new LambdaParametersFix());
+        }
+      }
+    };
   }
 
-  @Override
-  public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
-    final PsiParameterList parameterList = PsiTreeUtil.getParentOfType(element, PsiParameterList.class);
-    if (parameterList == null) return false;
+  private static boolean isApplicable(@NotNull PsiParameterList parameterList) {
     final PsiElement parent = parameterList.getParent();
     if (!(parent instanceof PsiLambdaExpression)) return false;
     final PsiLambdaExpression expression = (PsiLambdaExpression)parent;
@@ -73,9 +72,9 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti
 
           final PsiTypeParameter[] typeParameters = method.getTypeParameters();
           final PsiExpression[] arguments = ((PsiExpressionList)lambdaParent).getExpressions();
-          final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
+          final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(parameterList.getProject());
           arguments[idx] = javaPsiFacade.getElementFactory().createExpressionFromText(
-            "(" + StringUtil.join(expression.getParameterList().getParameters(), parameter -> parameter.getName(), ", ") + ") -> {}", expression);
+            "(" + StringUtil.join(expression.getParameterList().getParameters(), PsiParameter::getName, ", ") + ") -> {}", expression);
           final PsiParameter[] methodParams = method.getParameterList().getParameters();
           final PsiSubstitutor substitutor = javaPsiFacade.getResolveHelper()
             .inferTypeArguments(typeParameters, methodParams, arguments, ((MethodCandidateInfo)resolveResult).getSiteSubstitutor(),
@@ -85,8 +84,7 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti
             final PsiType psiType = substitutor.substitute(parameter);
             if (psiType == null || dependsOnTypeParams(psiType, expression, parameter)) return false;
           }
-          
-          
+
           final PsiType paramType;
           if (idx < methodParams.length) {
             paramType = methodParams[idx].getType();
@@ -107,12 +105,6 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti
     return false;
   }
 
-  @Override
-  public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
-    final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class);
-    removeTypes(lambdaExpression);
-  }
-
   private static void removeTypes(PsiLambdaExpression lambdaExpression) {
     if (lambdaExpression != null) {
       final PsiParameter[] parameters = lambdaExpression.getParameterList().getParameters();
@@ -121,7 +113,7 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti
         text = parameters[0].getName();
       }
       else {
-        text = "(" + StringUtil.join(parameters, parameter -> parameter.getName(), ", ") + ")";
+        text = "(" + StringUtil.join(parameters, PsiParameter::getName, ", ") + ")";
       }
       final PsiLambdaExpression expression = (PsiLambdaExpression)JavaPsiFacade.getElementFactory(lambdaExpression.getProject())
         .createExpressionFromText(text + "->{}", lambdaExpression);
@@ -135,4 +127,29 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti
     return LambdaUtil.depends(type, new LambdaUtil.TypeParamsChecker(expr, PsiUtil
       .resolveGenericsClassInType(LambdaUtil.getFunctionalInterfaceType(expr, false)).getElement()), param2Check);
   }
+
+  private static class LambdaParametersFix implements LocalQuickFix {
+    @Nls
+    @NotNull
+    @Override
+    public String getName() {
+      return getFamilyName();
+    }
+
+    @Nls
+    @NotNull
+    @Override
+    public String getFamilyName() {
+      return "Remove redundant types";
+    }
+
+    @Override
+    public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
+      final PsiElement element = descriptor.getPsiElement();
+      final PsiElement parent = element.getParent();
+      if (parent instanceof PsiLambdaExpression) {
+        removeTypes((PsiLambdaExpression)parent);
+      }
+    }
+  }
 }
index 31fa42faa53a951b49904bdcca8cbeb67958c45a..2583ea48770bc7538c15d1225560ba644cb8b79d 100644 (file)
@@ -19,13 +19,10 @@ import com.intellij.openapi.progress.ProgressIndicator;
 import com.intellij.openapi.progress.ProgressIndicatorProvider;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.roots.ProjectFileIndex;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.vfs.VirtualFileManager;
 import com.intellij.openapi.vfs.VirtualFileWithId;
 import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
-import com.intellij.psi.search.DelegatingGlobalSearchScope;
-import com.intellij.psi.search.EverythingGlobalScope;
-import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.psi.stubsHierarchy.HierarchyService;
 import com.intellij.psi.util.CachedValue;
 import com.intellij.psi.util.CachedValueProvider;
@@ -33,17 +30,18 @@ import com.intellij.psi.util.CachedValuesManager;
 import com.intellij.psi.util.PsiModificationTracker;
 import com.intellij.util.CachedValueBase;
 import com.intellij.util.indexing.FileBasedIndex;
+import com.intellij.util.indexing.FileBasedIndexImpl;
 import org.jetbrains.annotations.NotNull;
 
+import java.util.BitSet;
+
 public class HierarchyServiceImpl extends HierarchyService {
   private static final SingleClassHierarchy EMPTY_HIERARCHY = new SingleClassHierarchy(Symbol.ClassSymbol.EMPTY_ARRAY);
   private final Project myProject;
-  private final ProjectFileIndex myFileIndex;
   private final CachedValue<SingleClassHierarchy> myHierarchy;
 
   public HierarchyServiceImpl(Project project) {
     myProject = project;
-    myFileIndex = ProjectFileIndex.SERVICE.getInstance(project);
     myHierarchy = CachedValuesManager.getManager(project).createCachedValue(
       () -> CachedValueProvider.Result.create(buildHierarchy(), PsiModificationTracker.MODIFICATION_COUNT),
       false);
@@ -69,38 +67,56 @@ public class HierarchyServiceImpl extends HierarchyService {
   private SingleClassHierarchy buildHierarchy() {
     Symbols symbols = new Symbols();
     StubEnter stubEnter = new StubEnter(symbols);
+    IdSets idSets = IdSets.getIdSets(myProject);
 
-    loadUnits(false, symbols.myNameEnvironment, stubEnter);
+    loadUnits(idSets.libraryFiles, StubHierarchyIndex.BINARY_FILES, symbols.myNameEnvironment, stubEnter);
     stubEnter.connect1();
 
-    loadUnits(true, symbols.myNameEnvironment, stubEnter);
+    loadUnits(idSets.sourceFiles, StubHierarchyIndex.SOURCE_FILES, symbols.myNameEnvironment, stubEnter);
     stubEnter.connect2();
 
     return symbols.createHierarchy();
   }
 
-  private void loadUnits(boolean sourceMode, NameEnvironment names, StubEnter stubEnter) {
-    GlobalSearchScope scope = new DelegatingGlobalSearchScope(new EverythingGlobalScope(myProject)) {
+  private void loadUnits(BitSet files, int indexKey, NameEnvironment names, StubEnter stubEnter) {
+    ProgressIndicator indicator = ProgressIndicatorProvider.getGlobalProgressIndicator();
+
+    FileBasedIndexImpl index = (FileBasedIndexImpl)FileBasedIndex.getInstance();
+    index.processAllValues(StubHierarchyIndex.INDEX_ID, indexKey, myProject, new FileBasedIndexImpl.IdValueProcessor<IndexTree.Unit>() {
+      int count = 0;
       @Override
-      public boolean contains(@NotNull VirtualFile file) {
-        return sourceMode ? myFileIndex.isInSourceContent(file) : myFileIndex.isInLibraryClasses(file);
+      public boolean process(int fileId, IndexTree.Unit unit) {
+        if (indicator != null && ++count % 128 == 0) indicator.checkCanceled();
+        if (files.get(fileId)) {
+          QualifiedName pkg = unit.myPackageName.length == 0 ? null : names.myNamesEnumerator.getFullName(unit.myPackageName, true);
+          stubEnter.unitEnter(Translator.internNames(names, unit, fileId, pkg));
+        }
+        return true;
       }
-    };
-    ProgressIndicator indicator = ProgressIndicatorProvider.getGlobalProgressIndicator();
-    FileBasedIndex index = FileBasedIndex.getInstance();
-    for (String packageName : index.getAllKeys(StubHierarchyIndex.INDEX_ID, myProject)) {
-      QualifiedName pkg = StringUtil.isEmpty(packageName) ? null : names.fromString(packageName, true);
-      index.processValues(StubHierarchyIndex.INDEX_ID, packageName, null, new FileBasedIndex.ValueProcessor<IndexTree.Unit>() {
-        int count = 0;
+    });
+  }
+
+  private static class IdSets {
+    final BitSet sourceFiles = new BitSet();
+    final BitSet libraryFiles = new BitSet();
 
-        @Override
-        public boolean process(VirtualFile file, IndexTree.Unit unit) {
-          if (indicator != null && ++count % 128 == 0) indicator.checkCanceled();
-          stubEnter.unitEnter(Translator.internNames(names, unit, ((VirtualFileWithId)file).getId(), pkg));
+    static IdSets getIdSets(@NotNull Project project) {
+      return CachedValuesManager.getManager(project).getCachedValue(project, () -> {
+        IdSets answer = new IdSets();
+        ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project);
+        FileBasedIndex.getInstance().iterateIndexableFiles(file -> {
+          if (!file.isDirectory() && file instanceof VirtualFileWithId) {
+            if (index.isInSourceContent(file)) {
+              answer.sourceFiles.set(((VirtualFileWithId) file).getId());
+            }
+            else if (index.isInLibraryClasses(file)) {
+              answer.libraryFiles.set(((VirtualFileWithId) file).getId());
+            }
+          }
           return true;
-        }
-      }, scope);
+        }, project, ProgressIndicatorProvider.getGlobalProgressIndicator());
+        return CachedValueProvider.Result.create(answer, ProjectRootManager.getInstance(project), VirtualFileManager.VFS_STRUCTURE_MODIFICATIONS);
+      });
     }
   }
-
 }
index 550c33b9c74e8174d7c44c7cf84f7e5c4855e8d9..616ea7213f3cd0e9d6c34e7cd2ec296328f659db 100644 (file)
@@ -18,7 +18,6 @@ package com.intellij.psi.stubsHierarchy.impl;
 import com.intellij.ide.highlighter.JavaClassFileType;
 import com.intellij.ide.highlighter.JavaFileType;
 import com.intellij.openapi.fileTypes.FileType;
-import com.intellij.openapi.util.Pair;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.PsiModifier;
 import com.intellij.psi.PsiNameHelper;
@@ -39,7 +38,10 @@ import com.intellij.util.indexing.FileContent;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 public class JavaStubIndexer extends StubHierarchyIndexer {
 
@@ -61,7 +63,7 @@ public class JavaStubIndexer extends StubHierarchyIndexer {
 
   @Nullable
   @Override
-  public List<Pair<String, Unit>> indexFile(@NotNull FileContent content) {
+  public Unit indexFile(@NotNull FileContent content) {
     Stub stubTree = StubTreeBuilder.buildStubTree(content);
     if (!(stubTree instanceof PsiJavaFileStub)) return null;
 
@@ -87,7 +89,7 @@ public class JavaStubIndexer extends StubHierarchyIndexer {
     ClassDecl[] classes = classList.isEmpty() ? ClassDecl.EMPTY_ARRAY : classList.toArray(new ClassDecl[classList.size()]);
     Import[] imports = importList.isEmpty() ? Import.EMPTY_ARRAY : importList.toArray(new Import[importList.size()]);
     byte type = javaFileStub.isCompiled() ? IndexTree.BYTECODE : IndexTree.JAVA;
-    return Collections.singletonList(Pair.create(javaFileStub.getPackageName(), new Unit(type, imports, classes)));
+    return new Unit(javaFileStub.getPackageName(), type, imports, classes);
   }
 
   @Nullable
index 4dd87cff7630bbbf259bdb979bdf1fb7fab7be7c..e97f18ff7bd46b4d7de7acddf15ee56d7897e4b9 100644 (file)
 package com.intellij.psi.stubsHierarchy.impl;
 
 import com.intellij.openapi.util.UserDataHolderBase;
-import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Arrays;
-import java.util.List;
 
 public class NameEnvironment extends UserDataHolderBase {
-
   public final QualifiedName empty;
   public final QualifiedName java_lang_Object;
   public final QualifiedName java_lang_Enum;
@@ -40,22 +38,7 @@ public class NameEnvironment extends UserDataHolderBase {
 
   @Nullable
   public QualifiedName fromString(String s, boolean create) {
-    List<String> comps = StringUtil.split(s, ".");
-    int[] ids = new int[comps.size()];
-    for (int i = 0; i < comps.size(); i++) {
-      int name = simpleName(comps.get(i), create);
-      if (name == NamesEnumerator.NO_NAME) {
-        return null;
-      }
-      ids[i] = name;
-    }
-    return myNamesEnumerator.getFullName(ids, create);
-  }
-
-  public int simpleName(String s, boolean create) {
-    if (s == null)
-      return NamesEnumerator.NO_NAME;
-    return myNamesEnumerator.getSimpleName(s, create);
+    return myNamesEnumerator.getFullName(IndexTree.hashQualifiedName(s), create);
   }
 
   public QualifiedName prefix(QualifiedName name) {
index 02ee1143574e826528460a76490bac9f33e30e7e..cde21cf6ca45405b2c8105a477a114a6e479b20e 100644 (file)
  */
 package com.intellij.psi.stubsHierarchy.impl;
 
-import com.intellij.util.ArrayUtil;
 import gnu.trove.TObjectHashingStrategy;
 import gnu.trove.TObjectIntHashMap;
-import org.jetbrains.annotations.Nullable;
 
 import java.util.Arrays;
 
 public class NamesEnumerator {
   final static int NO_NAME = 0;
 
-  private TObjectIntHashMap<byte[]> myAsciiMap = new TObjectIntHashMap<byte[]>(new TObjectHashingStrategy<byte[]>() {
-    @Override
-    public int computeHashCode(byte[] object) {
-      return Arrays.hashCode(object);
-    }
-
-    @Override
-    public boolean equals(byte[] o1, byte[] o2) {
-      return Arrays.equals(o1, o2);
-    }
-  });
-
-  private TObjectIntHashMap<String> myNonAsciiMap = new TObjectIntHashMap<String>();
-
-  TObjectIntHashMap<int[]> fullNameMap = new TObjectIntHashMap<int[]>(new TObjectHashingStrategy<int[]>() {
+  private final TObjectIntHashMap<int[]> myFullNameMap = new TObjectIntHashMap<int[]>(new TObjectHashingStrategy<int[]>() {
     @Override
     public int computeHashCode(int[] object) {
       return Arrays.hashCode(object);
@@ -50,38 +34,17 @@ public class NamesEnumerator {
       return Arrays.equals(o1, o2);
     }
   });
-
   private QualifiedName[] myQualifiedNames = new QualifiedName[0x8000];
 
   QualifiedName qualifiedName(int id) {
     return myQualifiedNames[id];
   }
 
-  public int getSimpleName(String s, boolean create) {
-    byte[] bytes = convertToBytesIfAsciiString(s);
-    if (bytes != null) {
-      int id = myAsciiMap.get(bytes);
-      if (id == 0 && create) {
-        id = myAsciiMap.size() + myNonAsciiMap.size() + 1;
-        myAsciiMap.put(bytes, id);
-      }
-      return id;
-    }
-    else {
-      int id = myNonAsciiMap.get(s);
-      if (id == 0 && create) {
-        id = myAsciiMap.size() + myNonAsciiMap.size() + 1;
-        myNonAsciiMap.put(s, id);
-      }
-      return id;
-    }
-  }
-
   public QualifiedName getFullName(int[] ids, boolean create) {
-    int id = fullNameMap.get(ids);
+    int id = myFullNameMap.get(ids);
     if (id == 0 && create) {
-      id = fullNameMap.size() + 1;
-      fullNameMap.put(ids, id);
+      id = myFullNameMap.size() + 1;
+      myFullNameMap.put(ids, id);
       ensureFullCapacity(id);
       myQualifiedNames[id] = new QualifiedName(id, ids);
     }
@@ -104,20 +67,4 @@ public class NamesEnumerator {
     return currentLength;
   }
 
-  @Nullable
-  public static byte[] convertToBytesIfAsciiString(CharSequence name) {
-    int length = name.length();
-    if (length == 0) return ArrayUtil.EMPTY_BYTE_ARRAY;
-
-    byte[] bytes = new byte[length];
-    for (int i = 0; i < length; i++) {
-      char c = name.charAt(i);
-      if (c >= 128) {
-        return null;
-      }
-      bytes[i] = (byte)c;
-    }
-    return bytes;
-  }
-
 }
index 728a39f29c217475b11e372488c3c0d72c3b2401..77dab13e8492d875a3b43a8926bf72bc3764c22b 100644 (file)
@@ -88,7 +88,7 @@ public class StubEnter {
       supers = myNameEnvironment.annotation;
     }
 
-    ClassSymbol classSymbol = mySymbols.enterClass(tree.myClassAnchor, flags, tree.myName, owner, info, supers, myStubHierarchyConnector);
+    ClassSymbol classSymbol = mySymbols.enterClass(tree.myClassAnchor, flags, tree.myName, owner, info, supers);
 
     if (uncompleted != null)  {
       uncompleted.add(classSymbol);
@@ -100,14 +100,14 @@ public class StubEnter {
 
   public void connect1() {
     for (ClassSymbol classSymbol : uncompleted) {
-      classSymbol.connect();
+      classSymbol.connect(myStubHierarchyConnector);
     }
     uncompleted = new ArrayList<ClassSymbol>();
   }
 
   public void connect2() {
     for (ClassSymbol classSymbol : uncompleted) {
-      classSymbol.connect();
+      classSymbol.connect(myStubHierarchyConnector);
     }
     uncompleted = null;
   }
index 31b84f114fd00b826f8034889fdc84f73540f0df..f1c3e41117cecfcbf8a37625ebc86440b26aa0c1 100644 (file)
@@ -26,14 +26,14 @@ public class StubHierarchyConnector {
 
   protected StubHierarchyConnector(NameEnvironment nameEnvironment, Symbols symbols) {
     this.myNameEnvironment = nameEnvironment;
-    myResolve = new StubResolver(symbols);
+    myResolve = new StubResolver(symbols, this);
   }
 
   void connect(Symbol sym) {
     Symbol.ClassSymbol c = (Symbol.ClassSymbol) sym;
 
     if (c.myOwner instanceof Symbol.ClassSymbol) {
-      ((Symbol.ClassSymbol)c.myOwner).connect();
+      ((Symbol.ClassSymbol)c.myOwner).connect(this);
     }
 
     // Determine supertype.
@@ -67,6 +67,7 @@ public class StubHierarchyConnector {
         c.mySuperClasses = Symbol.ClassSymbol.EMPTY_ARRAY;
       }
       else {
+        //noinspection SuspiciousToArrayCall
         c.mySuperClasses = supertypes.toArray(new Symbol.ClassSymbol[supertypes.size()]);
       }
     }
index 2550e2fb528aae37628a75110ccc357445ab58f5..e695897cfe8bf98fcfff1abd3315d8f3abc7013b 100644 (file)
@@ -18,47 +18,42 @@ package com.intellij.psi.stubsHierarchy.impl;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.project.ProjectManager;
 import com.intellij.openapi.roots.ProjectFileIndex;
-import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
 import com.intellij.psi.impl.java.stubs.index.JavaUnitDescriptor;
 import com.intellij.psi.stubsHierarchy.StubHierarchyIndexer;
 import com.intellij.util.indexing.*;
 import com.intellij.util.io.DataExternalizer;
-import com.intellij.util.io.EnumeratorStringDescriptor;
+import com.intellij.util.io.EnumeratorIntegerDescriptor;
 import com.intellij.util.io.KeyDescriptor;
 import org.jetbrains.annotations.NotNull;
 
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collections;
 
 /**
  * @author peter
  */
-public class StubHierarchyIndex extends FileBasedIndexExtension<String, IndexTree.Unit> implements PsiDependentIndex {
-  static final ID<String, IndexTree.Unit> INDEX_ID = ID.create("jvm.hierarchy");
+public class StubHierarchyIndex extends FileBasedIndexExtension<Integer, IndexTree.Unit> implements PsiDependentIndex {
+  public static final int BINARY_FILES = 0;
+  public static final int SOURCE_FILES = 1;
+  static final ID<Integer, IndexTree.Unit> INDEX_ID = ID.create("jvm.hierarchy");
   private static final StubHierarchyIndexer[] ourIndexers = StubHierarchyIndexer.EP_NAME.getExtensions();
 
   @NotNull
   @Override
-  public ID<String, IndexTree.Unit> getName() {
+  public ID<Integer, IndexTree.Unit> getName() {
     return INDEX_ID;
   }
 
   @NotNull
   @Override
-  public DataIndexer<String, IndexTree.Unit, FileContent> getIndexer() {
+  public DataIndexer<Integer, IndexTree.Unit, FileContent> getIndexer() {
     return inputData -> {
       for (StubHierarchyIndexer indexer : ourIndexers) {
-        List<Pair<String, IndexTree.Unit>> pairs = indexer.handlesFile(inputData.getFile()) ? indexer.indexFile(inputData) : null;
-        if (pairs != null && !pairs.isEmpty()) {
-          Map<String, IndexTree.Unit> answer = new HashMap<>();
-          for (Pair<String, IndexTree.Unit> entry : pairs) {
-            if (entry.second.myDecls.length > 0) {
-              answer.put(StringUtil.notNullize(entry.first), entry.second);
-            }
-          }
-          return answer;
+        IndexTree.Unit unit = indexer.handlesFile(inputData.getFile()) ? indexer.indexFile(inputData) : null;
+        if (unit != null && unit.myDecls.length > 0) {
+          return Collections.singletonMap(inputData.getFile().getFileType().isBinary() ? BINARY_FILES : SOURCE_FILES, unit);
         }
       }
       return Collections.emptyMap();
@@ -67,8 +62,8 @@ public class StubHierarchyIndex extends FileBasedIndexExtension<String, IndexTre
 
   @NotNull
   @Override
-  public KeyDescriptor<String> getKeyDescriptor() {
-    return EnumeratorStringDescriptor.INSTANCE;
+  public KeyDescriptor<Integer> getKeyDescriptor() {
+    return EnumeratorIntegerDescriptor.INSTANCE;
   }
 
   @NotNull
@@ -79,7 +74,7 @@ public class StubHierarchyIndex extends FileBasedIndexExtension<String, IndexTre
 
   @Override
   public int getVersion() {
-    return IndexTree.STUB_HIERARCHY_ENABLED ? 2 + Arrays.stream(ourIndexers).mapToInt(StubHierarchyIndexer::getVersion).sum() : 0;
+    return IndexTree.STUB_HIERARCHY_ENABLED ? 4 + Arrays.stream(ourIndexers).mapToInt(StubHierarchyIndexer::getVersion).sum() : 0;
   }
 
   @NotNull
index 527a62c33fb7dc9c18eec7a14f117aeeccd21dd4..d34cedbe152ffd2ec7d0cc958a7455706080c285 100644 (file)
@@ -28,10 +28,12 @@ import java.util.Set;
 public class StubResolver {
   private final Symbols mySymbols;
   private final NameEnvironment myNameEnvironment;
+  private final StubHierarchyConnector myConnector;
 
-  public StubResolver(Symbols symbols) {
+  public StubResolver(Symbols symbols, StubHierarchyConnector connector) {
     this.mySymbols = symbols;
     this.myNameEnvironment = symbols.myNameEnvironment;
+    myConnector = connector;
   }
 
   // resolve class `sym` extends/implements `baseId`
@@ -97,7 +99,7 @@ public class StubResolver {
     }
   }
 
-  private static void findMemberType(Symbol s, int name, Set<Symbol> symbols, Set<Symbol> processed) throws IncompleteHierarchyException {
+  private void findMemberType(Symbol s, int name, Set<Symbol> symbols, Set<Symbol> processed) throws IncompleteHierarchyException {
     if (!processed.add(s)) {
       return;
     }
@@ -130,9 +132,9 @@ public class StubResolver {
     }
   }
 
-  private static void findInheritedMemberType(Symbol.ClassSymbol c, int name, Set<Symbol> symbols, Set<Symbol> processed)
+  private void findInheritedMemberType(Symbol.ClassSymbol c, int name, Set<Symbol> symbols, Set<Symbol> processed)
     throws IncompleteHierarchyException {
-    for (Symbol.ClassSymbol st : c.getSuperClasses())
+    for (Symbol.ClassSymbol st : c.getSuperClasses(myConnector))
       findMemberType(st, name, symbols, processed);
   }
 
@@ -194,13 +196,13 @@ public class StubResolver {
   }
 
   // handling of import static `tsym.name` as
-  private static void importNamedStatic(final Symbol.ClassSymbol tsym, final int name, final Set<Symbol> symbols) throws IncompleteHierarchyException {
+  private void importNamedStatic(final Symbol.ClassSymbol tsym, final int name, final Set<Symbol> symbols) throws IncompleteHierarchyException {
     new Object() {
       Set<Symbol> processed = new HashSet<Symbol>();
       void importFrom(Symbol.ClassSymbol cs) throws IncompleteHierarchyException {
         if (cs == null || !processed.add(cs))
           return;
-        for (Symbol.ClassSymbol c : cs.getSuperClasses())
+        for (Symbol.ClassSymbol c : cs.getSuperClasses(myConnector))
           importFrom(c);
         importMember(cs.members(), name, symbols, true);
       }
index bb1505d342ec1421c2e32df94882ced02cb56aa5..4ffcbed374fedba8c713f2ae9911d637392d6daf 100644 (file)
@@ -86,28 +86,27 @@ public abstract class Symbol {
   /** A class for class symbols
    */
   public static class ClassSymbol extends Symbol {
+    private static final int HIERARCHY_INCOMPLETE = 1 << 20;
+    private static final int CONNECT_STARTED = 1 << 21;
     public static final ClassSymbol[] EMPTY_ARRAY = new ClassSymbol[0];
-    public final StubClassAnchor myClassAnchor;
-    public ClassSymbol[] mySuperClasses;
-    public UnitInfo myUnitInfo;
-    public QualifiedName[] mySuperNames;
+
+    final StubClassAnchor myClassAnchor;
+    ClassSymbol[] mySuperClasses;
+    UnitInfo myUnitInfo;
+    QualifiedName[] mySuperNames;
     private ClassSymbol[] myMembers;
-    private StubHierarchyConnector myConnector;
-    private boolean myHierarchyIncomplete;
 
-    public ClassSymbol(StubClassAnchor classAnchor,
+    ClassSymbol(StubClassAnchor classAnchor,
                        int flags,
                        Symbol owner,
                        QualifiedName fullname,
                        int name,
                        UnitInfo unitInfo,
-                       QualifiedName[] supers,
-                       StubHierarchyConnector connector) {
+                       QualifiedName[] supers) {
       super(flags | IndexTree.CLASS, owner, fullname, name);
       this.myClassAnchor = classAnchor;
       this.mySuperNames = supers;
       this.myUnitInfo = unitInfo;
-      this.myConnector = connector;
     }
 
     @Override
@@ -115,18 +114,21 @@ public abstract class Symbol {
       return myClassAnchor.toString();
     }
 
-    public void connect() {
-      if (myConnector != null) {
-        StubHierarchyConnector c = myConnector;
-        myConnector = null;
-        c.connect(this);
+    void connect(StubHierarchyConnector connector) {
+      if (!isConnectStarted()) {
+        myFlags = BitUtil.set(myFlags, CONNECT_STARTED, true);
+        connector.connect(this);
       }
     }
 
+    private boolean isConnectStarted() {
+      return BitUtil.isSet(myFlags, CONNECT_STARTED);
+    }
+
     @NotNull
-    public ClassSymbol[] getSuperClasses() throws IncompleteHierarchyException {
-      connect();
-      if (myHierarchyIncomplete) {
+    ClassSymbol[] getSuperClasses(StubHierarchyConnector connector) throws IncompleteHierarchyException {
+      connect(connector);
+      if (isHierarchyIncomplete()) {
         throw IncompleteHierarchyException.INSTANCE;
       }
       return rawSuperClasses();
@@ -134,11 +136,11 @@ public abstract class Symbol {
 
     @NotNull
     ClassSymbol[] rawSuperClasses() {
-      assert myConnector == null;
+      assert isConnectStarted();
       return mySuperClasses == null ? EMPTY_ARRAY : mySuperClasses;
     }
 
-    public boolean isCompiled() {
+    boolean isCompiled() {
       return BitUtil.isSet(myFlags, IndexTree.COMPILED);
     }
 
@@ -154,11 +156,11 @@ public abstract class Symbol {
       mySuperClasses = EMPTY_ARRAY;
       mySuperNames = null;
       myUnitInfo = null;
-      myHierarchyIncomplete = true;
+      myFlags = BitUtil.set(myFlags, HIERARCHY_INCOMPLETE, true);
     }
 
     boolean isHierarchyIncomplete() {
-      return myHierarchyIncomplete;
+      return BitUtil.isSet(myFlags, HIERARCHY_INCOMPLETE);
     }
 
     boolean hasAmbiguousSupers() {
index 42feaf324509554af48dc4c7bf1049b5be71b52f..13017b18ab462fdcba74741f25bdf5d131a7047f 100644 (file)
@@ -63,10 +63,10 @@ public class Symbols {
     return (ClassSymbol[])cs;
   }
 
-  public ClassSymbol enterClass(ClassAnchor classAnchor, int flags, int shortName, Symbol owner, UnitInfo info, QualifiedName[] supers, StubHierarchyConnector connector) {
+  public ClassSymbol enterClass(ClassAnchor classAnchor, int flags, int shortName, Symbol owner, UnitInfo info, QualifiedName[] supers) {
     QualifiedName qualifiedName = myNameEnvironment.qualifiedName(owner, shortName);
     StubClassAnchor stubClassAnchor = new StubClassAnchor(myClassSymbols.size(), classAnchor);
-    ClassSymbol c = new ClassSymbol(stubClassAnchor, flags, owner, qualifiedName, shortName, info, supers, connector);
+    ClassSymbol c = new ClassSymbol(stubClassAnchor, flags, owner, qualifiedName, shortName, info, supers);
     myClassSymbols.add(c);
     putClassByName(c);
     return c;
index 0ad3c8b8d8317c312b7621941e8e4c9657115550..1367d003dd4ee3bda30a0fed5e4160fa35f57b86 100644 (file)
 package com.intellij.psi.stubsHierarchy.impl;
 
 import com.intellij.openapi.util.Key;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.PsiNameHelper;
 import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
 import com.intellij.psi.stubsHierarchy.stubs.*;
 import com.intellij.util.BitUtil;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
-import java.util.List;
 
 public class Translator {
   private static final Key<long[]> DEFAULT_JAVA_IMPORTS_KEY = Key.create("java_imports");
@@ -91,11 +88,10 @@ public class Translator {
   }
 
   private static ClassDeclaration processClassDecl(NameEnvironment nameEnvironment, int fileId, IndexTree.ClassDecl def) {
-    String stubName = def.myName;
-    int name = stubName == null ? 0 : nameEnvironment.simpleName(stubName, true);
+    int name = def.myName;
     ArrayList<QualifiedName> superList = new ArrayList<QualifiedName>();
-    for (String aSuper : def.mySupers) {
-      superList.add(id(nameEnvironment, aSuper));
+    for (int[] aSuper : def.mySupers) {
+      superList.add(nameEnvironment.concat(aSuper, true));
     }
     if (BitUtil.isSet(def.myMods, IndexTree.ENUM)) {
       superList.add(nameEnvironment.java_lang_Enum);
@@ -130,21 +126,8 @@ public class Translator {
   }
 
   private static long processImport(NameEnvironment nameEnvironment, IndexTree.Import anImport) {
-    QualifiedName fullname = nameEnvironment.fromString(anImport.myFullname, true);
-    int aliasName = anImport.myAlias == null ? 0 : nameEnvironment.simpleName(anImport.myAlias, true);
-    return Import.mkImport(fullname, anImport.myStaticImport, anImport.myOnDemand, aliasName);
+    QualifiedName fullname = nameEnvironment.myNamesEnumerator.getFullName(anImport.myFullname, true);
+    return Import.mkImport(fullname, anImport.myStaticImport, anImport.myOnDemand, anImport.myAlias);
   }
 
-  private static QualifiedName id(NameEnvironment nameEnvironment, String s) {
-    s = PsiNameHelper.getQualifiedClassName(s, true);
-    List<String> ids = StringUtil.split(s, ".");
-    int[] comps = new int[ids.size()];
-    int i = 0;
-    for (String id : ids) {
-      int name = nameEnvironment.simpleName(id, true);
-      comps[i] = name;
-      i++;
-    }
-    return nameEnvironment.concat(comps, true);
-  }
 }
index b263d49ddfdc0edfc14cc18075a474ceb2a57460..6a6146434d54909dc4b6a468710d8da321909d17 100644 (file)
@@ -63,7 +63,7 @@ public class ExtractClassHandler implements ElementsHandler {
     if (cannotRefactorMessage != null)  {
       CommonRefactoringUtil.showErrorHint(project, editor, 
                                           RefactorJBundle.message("cannot.perform.the.refactoring") + cannotRefactorMessage, 
-                                          null, getHelpID());
+                                          ExtractClassProcessor.REFACTORING_NAME, getHelpID());
       return;
     }
     new ExtractClassDialog(containingClass, selectedMember).show();
index 1e92218a183ece91d33ae7f39ecd96d97f703820..b0f0236075f0a1edc5614ecc6ef1b9da33167d9b 100644 (file)
@@ -66,6 +66,7 @@ import java.util.*;
 
 public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor {
   private static final Logger logger = Logger.getInstance("com.siyeh.rpp.extractclass.ExtractClassProcessor");
+  @NonNls public static final String REFACTORING_NAME = "Extract Delegate";
 
   private final PsiClass sourceClass;
   private final List<PsiField> fields;
index bc8d742039b629387b15523043cabadebc7eca3b..ad2fddadbe36198aeca8112737ccf97031fcd83b 100644 (file)
@@ -16,6 +16,7 @@
 package com.intellij.psi.impl.java.stubs.index;
 
 import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
+import com.intellij.util.BitUtil;
 import com.intellij.util.io.DataExternalizer;
 import com.intellij.util.io.DataInputOutputUtil;
 import org.jetbrains.annotations.NotNull;
@@ -24,18 +25,34 @@ import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
 
+import static com.intellij.psi.impl.java.stubs.index.JavaUnitDescriptor.ImportFlags.*;
+
 public class JavaUnitDescriptor implements DataExternalizer<IndexTree.Unit> {
   public static final JavaUnitDescriptor INSTANCE = new JavaUnitDescriptor();
 
+  private static void writeIntArray(DataOutput out, int[] array) throws IOException {
+    DataInputOutputUtil.writeINT(out, array.length);
+    for (int i : array) {
+      out.writeInt(i);
+    }
+  }
+  private static int[] readIntArray(DataInput in) throws IOException {
+    int length = DataInputOutputUtil.readINT(in);
+    int[] result = new int[length];
+    for (int i = 0; i < length; i++) {
+      result[i] = in.readInt();
+    }
+    return result;
+  }
+
   @Override
   public void save(@NotNull DataOutput out, IndexTree.Unit value) throws IOException {
+    writeIntArray(out, value.myPackageName);
     out.writeByte(value.myUnitType);
     if (value.myUnitType != IndexTree.BYTECODE) {
       DataInputOutputUtil.writeINT(out, value.imports.length);
       for (IndexTree.Import anImport : value.imports) {
-        out.writeUTF(anImport.myFullname);
-        out.writeBoolean(anImport.myStaticImport);
-        out.writeBoolean(anImport.myOnDemand);
+        writeImport(out, anImport);
       }
     }
     // class Declaration
@@ -46,12 +63,12 @@ public class JavaUnitDescriptor implements DataExternalizer<IndexTree.Unit> {
   }
 
   private void saveClassDecl(@NotNull DataOutput out, IndexTree.ClassDecl value) throws IOException {
-    out.writeInt(value.myStubId);
+    DataInputOutputUtil.writeINT(out, value.myStubId);
     DataInputOutputUtil.writeINT(out, value.myMods);
-    out.writeUTF(value.myName == null ? "" : value.myName);
+    out.writeInt(value.myName);
     DataInputOutputUtil.writeINT(out, value.mySupers.length);
-    for (String aSuper : value.mySupers) {
-      out.writeUTF(aSuper);
+    for (int[] aSuper : value.mySupers) {
+      writeIntArray(out, aSuper);
     }
     DataInputOutputUtil.writeINT(out, value.myDecls.length);
     for (IndexTree.Decl def : value.myDecls) {
@@ -75,31 +92,29 @@ public class JavaUnitDescriptor implements DataExternalizer<IndexTree.Unit> {
 
   @Override
   public IndexTree.Unit read(@NotNull DataInput in) throws IOException {
+    int[] pid = readIntArray(in);
     byte type = in.readByte();
     IndexTree.Import[] imports = IndexTree.Import.EMPTY_ARRAY;
     if (type != IndexTree.BYTECODE) {
       imports = new IndexTree.Import[DataInputOutputUtil.readINT(in)];
       for (int i = 0; i < imports.length; i++) {
-        imports[i] = new IndexTree.Import(in.readUTF(), in.readBoolean(), in.readBoolean(), null);
+        imports[i] = readImport(in);
       }
     }
     IndexTree.ClassDecl[] classes = new IndexTree.ClassDecl[DataInputOutputUtil.readINT(in)];
     for (int i = 0; i < classes.length; i++) {
       classes[i] = readClassDecl(in);
     }
-    return new IndexTree.Unit(type, imports, classes);
+    return new IndexTree.Unit(pid, type, imports, classes);
   }
 
   private IndexTree.ClassDecl readClassDecl(DataInput in) throws IOException {
-    int stubId = in.readInt();
+    int stubId = DataInputOutputUtil.readINT(in);
     int mods = DataInputOutputUtil.readINT(in);
-    String name = in.readUTF();
-    if (name.isEmpty()) {
-      name = null;
-    }
-    String[] supers = new String[DataInputOutputUtil.readINT(in)];
+    int name = in.readInt();
+    int[][] supers = new int[DataInputOutputUtil.readINT(in)][];
     for (int i = 0; i < supers.length; i++) {
-      supers[i] = in.readUTF();
+      supers[i] = readIntArray(in);
     }
     IndexTree.Decl[] decls = new IndexTree.Decl[DataInputOutputUtil.readINT(in)];
     for (int i = 0; i < decls.length; i++) {
@@ -122,4 +137,32 @@ public class JavaUnitDescriptor implements DataExternalizer<IndexTree.Unit> {
     }
   }
 
+  interface ImportFlags {
+    int IS_STATIC = 1;
+    int IS_ON_DEMAND = 2;
+    int HAS_ALIAS = 4;
+  }
+
+  private static void writeImport(@NotNull DataOutput out, IndexTree.Import anImport) throws IOException {
+    writeIntArray(out, anImport.myFullname);
+    boolean hasAlias = anImport.myAlias != 0;
+    int flags = 0;
+    flags = BitUtil.set(flags, IS_STATIC, anImport.myStaticImport);
+    flags = BitUtil.set(flags, IS_ON_DEMAND, anImport.myOnDemand);
+    flags = BitUtil.set(flags, HAS_ALIAS, hasAlias);
+    out.writeByte(flags);
+    if (hasAlias) {
+      out.writeInt(anImport.myAlias);
+    }
+  }
+
+  @NotNull
+  private static IndexTree.Import readImport(@NotNull DataInput in) throws IOException {
+    int[] fullname = readIntArray(in);
+    int flags = in.readByte();
+    return new IndexTree.Import(fullname,
+                                BitUtil.isSet(flags, IS_STATIC), BitUtil.isSet(flags, IS_ON_DEMAND),
+                                BitUtil.isSet(flags, HAS_ALIAS) ? in.readInt() : 0);
+  }
+
 }
index ce9d1660222434c451ea138fd3b3dea7fd7497fc..4e0e8ac260fc9a861f9325593feb5d4cbc0f50a8 100644 (file)
 package com.intellij.psi.stubsHierarchy;
 
 import com.intellij.openapi.extensions.ExtensionPointName;
-import com.intellij.openapi.util.Pair;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
 import com.intellij.util.indexing.FileContent;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.List;
-
 /**
  * @author peter
  */
@@ -37,7 +34,7 @@ public abstract class StubHierarchyIndexer {
    * @return a list of pairs <packageName, compilation unit> for a specified file content
    */
   @Nullable
-  public abstract List<Pair<String, IndexTree.Unit>> indexFile(@NotNull FileContent content);
+  public abstract IndexTree.Unit indexFile(@NotNull FileContent content);
 
   public abstract boolean handlesFile(@NotNull VirtualFile file);
 
index 2148bd45b3cbf6160eff784ed48c1a59fad057e3..ef0e111566509d69302055226c32b84f9f344bd6 100644 (file)
  */
 package com.intellij.psi.util;
 
+import com.intellij.openapi.roots.FileIndexFacade;
+import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.util.containers.HashSet;
 import gnu.trove.THashMap;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -111,6 +115,7 @@ public class PsiSuperMethodUtil {
   public static Map<MethodSignature, Set<PsiMethod>> collectOverrideEquivalents(@NotNull PsiClass aClass) {
     final Map<MethodSignature, Set<PsiMethod>> overrideEquivalent =
       new THashMap<MethodSignature, Set<PsiMethod>>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
+    final GlobalSearchScope resolveScope = aClass.getResolveScope();
     PsiClass[] supers = aClass.getSupers();
     for (int i = 0; i < supers.length; i++) {
       PsiClass superClass = supers[i];
@@ -122,10 +127,12 @@ public class PsiSuperMethodUtil {
       if (subType) continue;
       final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY);
       for (HierarchicalMethodSignature hms : superClass.getVisibleSignatures()) {
-        final PsiMethod method = hms.getMethod();
+        PsiMethod method = hms.getMethod();
         if (MethodSignatureUtil.findMethodBySignature(aClass, method.getSignature(superClassSubstitutor), false) != null) continue;
-        final PsiClass containingClass = method.getContainingClass();
+        final PsiClass containingClass = correctClassByScope(method.getContainingClass(), resolveScope);
         if (containingClass == null) continue;
+        method = containingClass.findMethodBySignature(method, false);
+        if (method == null) continue;
         final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, aClass, PsiSubstitutor.EMPTY);
         if (containingClassSubstitutor == null) continue;
         final PsiSubstitutor finalSubstitutor =
@@ -141,4 +148,30 @@ public class PsiSuperMethodUtil {
     }
     return overrideEquivalent;
   }
+
+  @Nullable
+  public static PsiClass correctClassByScope(PsiClass psiClass, final GlobalSearchScope resolveScope) {
+    if (psiClass == null) return null;
+    String qualifiedName = psiClass.getQualifiedName();
+    if (qualifiedName == null) {
+      return psiClass;
+    }
+
+    PsiFile file = psiClass.getContainingFile();
+    if (file == null || !file.getViewProvider().isPhysical()) {
+      return psiClass;
+    }
+
+    final VirtualFile vFile = file.getVirtualFile();
+    if (vFile == null) {
+      return psiClass;
+    }
+
+    final FileIndexFacade index = FileIndexFacade.getInstance(file.getProject());
+    if (!index.isInSource(vFile) && !index.isInLibrarySource(vFile) && !index.isInLibraryClasses(vFile)) {
+      return psiClass;
+    }
+
+    return JavaPsiFacade.getInstance(psiClass.getProject()).findClass(qualifiedName, resolveScope);
+  }
 }
index f6521658c6dcd50ce5a19682552c24ba1915c2a9..c6063e0b05bdd434dd2aeb80d1858bca983b973f 100644 (file)
  */
 package com.intellij.psi.impl;
 
-import com.intellij.openapi.roots.FileIndexFacade;
-import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.pom.java.LanguageLevel;
 import com.intellij.psi.*;
 import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiSuperMethodUtil;
 import com.intellij.psi.util.PsiUtilCore;
 import com.intellij.util.Function;
 import com.intellij.util.containers.ContainerUtil;
@@ -56,7 +55,7 @@ class TypeCorrector extends PsiTypeMapper {
         final PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics();
         final PsiClass psiClass = classResolveResult.getElement();
         if (psiClass != null && classResolveResult.getSubstitutor() == PsiSubstitutor.EMPTY) {
-          final PsiClass mappedClass = mapClass(psiClass);
+          final PsiClass mappedClass = PsiSuperMethodUtil.correctClassByScope(psiClass, myResolveScope);
           if (mappedClass == null || mappedClass == psiClass) return (T) classType;
         }
       }
@@ -79,7 +78,7 @@ class TypeCorrector extends PsiTypeMapper {
 
     PsiUtilCore.ensureValid(psiClass);
 
-    final PsiClass mappedClass = mapClass(psiClass);
+    final PsiClass mappedClass = PsiSuperMethodUtil.correctClassByScope(psiClass, myResolveScope);
     if (mappedClass == null) return classType;
 
     PsiClassType mappedType = new PsiCorrectedClassType(classType.getLanguageLevel(),
@@ -89,31 +88,6 @@ class TypeCorrector extends PsiTypeMapper {
     return mappedType;
   }
 
-  @Nullable
-  private PsiClass mapClass(@NotNull PsiClass psiClass) {
-    String qualifiedName = psiClass.getQualifiedName();
-    if (qualifiedName == null) {
-      return psiClass;
-    }
-
-    PsiFile file = psiClass.getContainingFile();
-    if (file == null || !file.getViewProvider().isPhysical()) {
-      return psiClass;
-    }
-
-    final VirtualFile vFile = file.getVirtualFile();
-    if (vFile == null) {
-      return psiClass;
-    }
-
-    final FileIndexFacade index = FileIndexFacade.getInstance(file.getProject());
-    if (!index.isInSource(vFile) && !index.isInLibrarySource(vFile) && !index.isInLibraryClasses(vFile)) {
-      return psiClass;
-    }
-
-    return JavaPsiFacade.getInstance(psiClass.getProject()).findClass(qualifiedName, myResolveScope);
-  }
-
   @NotNull
   private PsiSubstitutor mapSubstitutor(PsiClass originalClass, PsiClass mappedClass, PsiSubstitutor substitutor) {
     PsiTypeParameter[] typeParameters = mappedClass.getTypeParameters();
index faf27c3a2d7bcbb8db4641a94190659ed98308eb..b7a148b21be187cfc41888915bab16b3ad36f838 100644 (file)
@@ -17,12 +17,19 @@ package com.intellij.psi.impl.java.stubs.hierarchy;
 
 
 import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiNameHelper;
+import com.intellij.util.ArrayUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Arrays;
+import java.util.List;
 
 public class IndexTree {
   public static final boolean STUB_HIERARCHY_ENABLED = Registry.is("java.hierarchy.service");
 
+  @SuppressWarnings("PointlessBitwiseExpression")
   public final static int PACKAGE = 1 << 0;
   public final static int CLASS = 1 << 1;
   public static final int STATIC       = 1 << 3;
@@ -36,15 +43,52 @@ public class IndexTree {
   public static final byte JAVA = 1;
   public static final byte GROOVY = 2;
 
+  private static int hashIdentifier(@Nullable String s) {
+    if (s == null) return 0;
+
+    // not using String.hashCode because this way there's less collisions for short package names like 'com'
+    int hash = 0;
+    for (int i = 0; i < s.length(); i++) {
+      hash = hash * 239 + s.charAt(i);
+    }
+    return hash;
+  }
+
+  public static int[] hashQualifiedName(@NotNull String qName) {
+    qName = PsiNameHelper.getQualifiedClassName(qName, true);
+    if (qName.isEmpty()) return ArrayUtil.EMPTY_INT_ARRAY;
+
+    List<String> components = StringUtil.split(qName, ".");
+    int[] result = new int[components.size()];
+    for (int i = 0; i < components.size(); i++) {
+      result[i] = hashIdentifier(components.get(i));
+    }
+    return result;
+  }
+
+  private static int[][] hashQualifiedNameArray(String[] supers) {
+    int[][] superHashes = new int[supers.length][];
+    for (int i = 0; i < supers.length; i++) {
+      superHashes[i] = hashQualifiedName(supers[i]);
+    }
+    return superHashes;
+  }
+
   public static class Unit {
+    @NotNull public final int[] myPackageName;
     public final byte myUnitType;
     public final Import[] imports;
     public final ClassDecl[] myDecls;
 
-    public Unit(byte unitType, Import[] imports, ClassDecl[] decls) {
-      this.myUnitType = unitType;
+    public Unit(@Nullable String packageName, byte unitType, Import[] imports, ClassDecl[] decls) {
+      this(hashQualifiedName(StringUtil.notNullize(packageName)), unitType, imports, decls);
+    }
+
+    public Unit(@NotNull int[] packageName, byte unitType, Import[] imports, ClassDecl[] decls) {
+      myPackageName = packageName;
+      myUnitType = unitType;
       this.imports = imports;
-      this.myDecls = decls;
+      myDecls = decls;
     }
 
     @Override
@@ -54,6 +98,8 @@ public class IndexTree {
 
       Unit unit = (Unit)o;
 
+      if (myUnitType != unit.myUnitType) return false;
+      if (!Arrays.equals(myPackageName, unit.myPackageName)) return false;
       if (!Arrays.equals(imports, unit.imports)) return false;
       if (!Arrays.equals(myDecls, unit.myDecls)) return false;
 
@@ -62,22 +108,33 @@ public class IndexTree {
 
     @Override
     public int hashCode() {
-      return Arrays.hashCode(myDecls);
+      int hash = myUnitType * 31 + Arrays.hashCode(myPackageName);
+      for (ClassDecl decl : myDecls) {
+        int name = decl.myName;
+        if (name != 0) {
+          return hash * 31 + name;
+        }
+      }
+      return hash;
     }
   }
 
   public static class Import {
     public static final Import[] EMPTY_ARRAY = new Import[0];
-    public final String myFullname;
+    public final int[] myFullname;
     public final boolean myStaticImport;
     public final boolean myOnDemand;
-    public final String myAlias;
+    public final int myAlias;
 
-    public Import(String fullname, boolean staticImport, boolean onDemand, String alias) {
-      this.myFullname = fullname;
-      this.myStaticImport = staticImport;
-      this.myOnDemand = onDemand;
-      this.myAlias = alias;
+    public Import(String fullname, boolean staticImport, boolean onDemand, @Nullable String alias) {
+      this(hashQualifiedName(fullname), staticImport, onDemand, hashIdentifier(alias));
+    }
+
+    public Import(int[] fullname, boolean staticImport, boolean onDemand, int alias) {
+      myFullname = fullname;
+      myStaticImport = staticImport;
+      myOnDemand = onDemand;
+      myAlias = alias;
     }
 
     @Override
@@ -89,18 +146,18 @@ public class IndexTree {
 
       if (myStaticImport != anImport.myStaticImport) return false;
       if (myOnDemand != anImport.myOnDemand) return false;
-      if (!myFullname.equals(anImport.myFullname)) return false;
-      if (myAlias != null ? !myAlias.equals(anImport.myAlias) : anImport.myAlias != null) return false;
+      if (!Arrays.equals(myFullname, anImport.myFullname)) return false;
+      if (myAlias != anImport.myAlias) return false;
 
       return true;
     }
 
     @Override
     public int hashCode() {
-      int result = myFullname.hashCode();
+      int result = Arrays.hashCode(myFullname);
       result = 31 * result + (myStaticImport ? 1 : 0);
       result = 31 * result + (myOnDemand ? 1 : 0);
-      result = 31 * result + (myAlias != null ? myAlias.hashCode() : 0);
+      result = 31 * result + myAlias;
       return result;
     }
   }
@@ -118,16 +175,20 @@ public class IndexTree {
     public static final ClassDecl[] EMPTY_ARRAY = new ClassDecl[0];
     public final int myStubId;
     public final int myMods;
-    public final String myName;
-    public final String[] mySupers;
+    public final int myName;
+    public final int[][] mySupers;
+
+    public ClassDecl(int stubId, int mods, @Nullable String name, String[] supers, Decl[] decls) {
+      this(stubId, mods, hashIdentifier(name), hashQualifiedNameArray(supers), decls);
+    }
 
-    public ClassDecl(int stubId, int mods, String name, String[] supers, Decl[] decls) {
+    public ClassDecl(int stubId, int mods, int name, int[][] supers, Decl[] decls) {
       super(decls);
       assert stubId > 0;
-      this.myStubId = stubId;
-      this.myMods = mods;
-      this.myName = name;
-      this.mySupers = supers;
+      myStubId = stubId;
+      myMods = mods;
+      myName = name;
+      mySupers = supers;
     }
 
     @Override
@@ -138,8 +199,8 @@ public class IndexTree {
       ClassDecl classDecl = (ClassDecl)o;
       if (myStubId != classDecl.myStubId) return false;
       if (myMods != classDecl.myMods) return false;
-      if (myName != null ? !myName.equals(classDecl.myName) : classDecl.myName != null) return false;
-      if (!Arrays.equals(mySupers, classDecl.mySupers)) return false;
+      if (myName != classDecl.myName) return false;
+      if (!Arrays.deepEquals(mySupers, classDecl.mySupers)) return false;
       if (!Arrays.equals(myDecls, classDecl.myDecls)) return false;
       return true;
     }
@@ -148,7 +209,7 @@ public class IndexTree {
     public int hashCode() {
       int result = myStubId;
       result = 31 * result + myMods;
-      result = 31 * result + (myName != null ? myName.hashCode() : 0);
+      result = 31 * result + myName;
       return result;
     }
   }
index 50b49e3b29b15fbcc9cf45539839bb29c2b3c754..18ed26bd5e43fd6666cbe05422fad0c427dd45e7 100644 (file)
@@ -237,9 +237,7 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements
                                           PsiType ret,
                                           JavaResolveResult result, 
                                           LanguageLevel languageLevel) {
-    PsiSubstitutor substitutor = result instanceof MethodCandidateInfo && !PsiPolyExpressionUtil.isMethodCallTypeDependsOnInference(call, method)
-                                 ? ((MethodCandidateInfo)result).getSiteSubstitutor()
-                                 : result.getSubstitutor();
+    PsiSubstitutor substitutor = result.getSubstitutor();
     PsiType substitutedReturnType = substitutor.substitute(ret);
     if (substitutedReturnType == null) {
       return TypeConversionUtil.erasure(ret);
index 89683098fc6b8665e3cb8353d80900e4627e6ac6..d785f80ad35f9c7524f058aab722e26db054a9d4 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
     void foo() {
       foo(<caret>);
index e72764fff0dc83f5cf3f9e1637ab507617d39664..768f011765122ae3ca24e79845d0647c57994eba 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 abstract class Test {
     int foo(boolean... args) {
       return foo(<caret>, args);
index 4844902fdf14daf002e03570f527c5f62435a74e..0bd44690c430ceee53a7e6a508d907d14817b858 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
     int foo() {
       return foo();
index b73c48ebd2df11a7667c9aaf75afb586450b5834..1f3d305ec5b1eb6811df4e912fa6dbb4b70d628f 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded constructor with default parameter value" "true"
+// "Generate overloaded constructor with default parameter values" "true"
 class Test {
     Test() {
       this(<caret>);
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterExistinMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterExistinMethod.java
new file mode 100644 (file)
index 0000000..d1e063f
--- /dev/null
@@ -0,0 +1,6 @@
+// "Generate overloaded method with default parameter values" "true"
+class Test {
+  void foo(){}
+  void foo(int ii){
+  }
+}
\ No newline at end of file
index decd3f141818d1fa1f0330a5915cb1a6694f4a83..7a3ddc85e93d6ab81ed162380029a5cd203f1130 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 interface Test {
     default void foo() {
       foo();
index 3f15183133d72a4c2c77ce73097806a44877da91..697c0e305b6a99ffc9533f3627e9460c1c855b65 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
     /**  
    */
index 1e89e83a3cb7cb95b175e742b2f2d784fe547272..971da0d8e6da37aceba831c4f29e900cba75e044 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
     int foo() {
       return foo(<caret>);
index 01e1bdab551bce2bc91cbbb80c7005acbaa25d24..eb84d0998b75dc039715cd2e42082fd85cb0609b 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 interface Test {
     static void foo() {
       foo();
index 57fb3563e0accf59136971388727ebab15477a6c..c392c5a863238172030781793646d044ccf63006 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
     <T> int foo(boolean... args) {
       return foo(<caret>, args);
index 68e2eaeec5649d5cc484dfa90a17207bc4951aa5..d9878cc69b41d50f4a36a99afda926d0aa12569a 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
     int foo(boolean... args) {
       return foo(<caret>, args);
index 48895a8251b2520ce2ca381a6151bc2de3185833..558e6e4c68f6d892e1259b0050d880c4647a5776 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
   void foo(int i<caret>i){
   }
index 320debae10f291eb9e284aaac55b09959bd72562..9080288f6fa881ba69440714f32c1d4b51e317c9 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 abstract class Test {
   abstract int foo(int i<caret>i, boolean... args);
 }
\ No newline at end of file
index 9a6ad6184854c505be85819290964bb123402215..97357c6b3e0ef03afd869c3c16e85479b5eb348c 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
   int foo(int i<caret>i){
     //comment1
index 7fe236b65cf4609ab4902e4d5e8cbb1f01c0945a..a8b8be8ba4b8da63bdbf0346a499161408f381e0 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded constructor with default parameter value" "true"
+// "Generate overloaded constructor with default parameter values" "true"
 class Test {
   Test(int i<caret>i){}
 }
\ No newline at end of file
index 52fa17401c5d41196fbd2e6096e222adf0aa169f..f8dbe503ccc702d4b0bceaf076273db6ebc70c82 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "false"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
   void foo(){}
   void foo(int i<caret>i){
index 1f960d28b21db3f60777f542352a25614f2b362e..8217a2c642fe122bb3c0fef48477f922aa74b6d0 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 interface Test {
   void foo(int i<caret>i);
 }
\ No newline at end of file
index 267cdf9f901a35705c8a9c38c959b9e5be17f7b3..c4906ebcfafb26661916139bd3a7a588bd33d8f8 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
   /**
    * @param i
index 4df7057f4e31a41da7156ba4ac34b7c4bfe01a58..056d8badf78bab08027de2cd5cc0796b53cf47a8 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
   int foo(int i<caret>i){
     return 1;
index 5ea839e503a6382c17fc5463d4c2725392590a35..f2026953d9f38f053d9004a7cd6798518205f3c3 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 interface Test {
   static void foo(int i<caret>i) {}
 }
\ No newline at end of file
index e55000a24f3740b93a3bc88eb414272f55f25f7b..4ab9ec7459fdfea10a52501056e416e393510bd8 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
   <T> int foo(T i<caret>i, boolean... args){
     return 1;
index 6ddbc5a9069cc706468f6c327310f9575d0f274d..7f6628882710b48f8e9c818083b7f44984a30e4c 100644 (file)
@@ -1,4 +1,4 @@
-// "Generate overloaded method with default parameter value" "true"
+// "Generate overloaded method with default parameter values" "true"
 class Test {
   int foo(int i<caret>i, boolean... args){
     return 1;
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/after1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/after1.java
deleted file mode 100644 (file)
index d0d5576..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// "Remove redundant 'else'" "true"
-class a {
-  void foo() {
-    int a = 0;
-    int b = 0;
-    if (a != b) {
-      return;
-    }
-      a = b;
-      a++;
-  }
-}
-
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/before1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/before1.java
deleted file mode 100644 (file)
index ea46098..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// "Remove redundant 'else'" "true"
-class a {
-  void foo() {
-    int a = 0;
-    int b = 0;
-    if (a != b) {
-      return;
-    } e<caret>lse {
-      a = b;
-    }
-    a++;
-  }
-}
-
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/beforeCanThrowException.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/beforeCanThrowException.java
deleted file mode 100644 (file)
index 8fd59ef..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// "Remove redundant 'else'" "false"
-import java.io.IOException;
-class a {
-  void foo(boolean condition) throws IOException{
-    if (condition) {
-      tMethod();
-    }
-    e<caret>lse {
-      System.out.println("else");
-    }
-  }
-
-  void tMethod() throws IOException {}
-}
-
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/beforeIfElseChain.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/beforeIfElseChain.java
deleted file mode 100644 (file)
index f702178..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// "Remove redundant 'else'" "false"
-class a {
-  void foo() {
-    int a = 0;
-    int b = 0;
-    if (a != b) {
-      a = 10;
-    } else if (a + 1 == b) {
-      return;
-    }
-    e<caret>lse {
-      a = b;
-    }
-    a++;
-  }
-}
-
diff --git a/java/java-tests/testData/codeInsight/multipleJdks/java7/p/I.java b/java/java-tests/testData/codeInsight/multipleJdks/java7/p/I.java
new file mode 100644 (file)
index 0000000..30e62b5
--- /dev/null
@@ -0,0 +1,4 @@
+package p;
+interface I {
+  default void foo();
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/multipleJdks/java7/p/UnrelatedDefaultsFromDifferentJdkVersions.java b/java/java-tests/testData/codeInsight/multipleJdks/java7/p/UnrelatedDefaultsFromDifferentJdkVersions.java
new file mode 100644 (file)
index 0000000..52e0518
--- /dev/null
@@ -0,0 +1,3 @@
+package p;
+
+public abstract class A implements I {}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/multipleJdks/java8/p/I.java b/java/java-tests/testData/codeInsight/multipleJdks/java8/p/I.java
new file mode 100644 (file)
index 0000000..30e62b5
--- /dev/null
@@ -0,0 +1,4 @@
+package p;
+interface I {
+  default void foo();
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/multipleJdks/java8/p/UnrelatedDefaultsFromDifferentJdkVersions.java b/java/java-tests/testData/codeInsight/multipleJdks/java8/p/UnrelatedDefaultsFromDifferentJdkVersions.java
new file mode 100644 (file)
index 0000000..ab93746
--- /dev/null
@@ -0,0 +1,8 @@
+package p;
+
+class EmptyValueIterator extends A implements ValueIterator {
+
+}
+
+interface ValueIterator extends I {}
+
diff --git a/java/java-tests/testData/codeInspection/redundantLambdaParameterType/InChain.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/InChain.java
new file mode 100644 (file)
index 0000000..7262e3b
--- /dev/null
@@ -0,0 +1,7 @@
+import java.util.stream.Stream;
+
+class InChain {
+  public static void main(String[] args) {
+    Stream.of("a").map((String<caret> s) -> s + "1").forEach(System.out::println);
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInspection/redundantLambdaParameterType/InChain_after.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/InChain_after.java
new file mode 100644 (file)
index 0000000..857e423
--- /dev/null
@@ -0,0 +1,7 @@
+import java.util.stream.Stream;
+
+class InChain {
+  public static void main(String[] args) {
+    Stream.of("a").map(s -> s + "1").forEach(System.out::println);
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/extractMethod/LocalVariableAnnotationsOrder.java b/java/java-tests/testData/refactoring/extractMethod/LocalVariableAnnotationsOrder.java
new file mode 100644 (file)
index 0000000..7fa69c1
--- /dev/null
@@ -0,0 +1,13 @@
+class C {
+  {
+    @B @A int i = 0;
+    System.out.println(i);
+  }
+
+  void f() {
+    <selection>@A @B int j = 0;
+    System.out.println(j);</selection>
+  }
+}
+@interface A {}
+@interface B {}
\ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/extractMethod/LocalVariableAnnotationsOrder_after.java b/java/java-tests/testData/refactoring/extractMethod/LocalVariableAnnotationsOrder_after.java
new file mode 100644 (file)
index 0000000..54630c8
--- /dev/null
@@ -0,0 +1,16 @@
+class C {
+  {
+      newMethod();
+  }
+
+  void f() {
+      newMethod();
+  }
+
+    private void newMethod() {
+        @A @B int j = 0;
+        System.out.println(j);
+    }
+}
+@interface A {}
+@interface B {}
\ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/extractMethod/LocalVariableModifierList.java b/java/java-tests/testData/refactoring/extractMethod/LocalVariableModifierList.java
new file mode 100644 (file)
index 0000000..d9d2f99
--- /dev/null
@@ -0,0 +1,11 @@
+class C {
+  {
+    int i = 0;
+    System.out.println(i);
+  }
+
+  void f() {
+    <selection>final int j = 0;
+    System.out.println(j);</selection>
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/extractMethod/LocalVariableModifierList_after.java b/java/java-tests/testData/refactoring/extractMethod/LocalVariableModifierList_after.java
new file mode 100644 (file)
index 0000000..e679236
--- /dev/null
@@ -0,0 +1,14 @@
+class C {
+  {
+      newMethod();
+  }
+
+  void f() {
+      newMethod();
+  }
+
+    private void newMethod() {
+        final int j = 0;
+        System.out.println(j);
+    }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/extractMethod/MethodAnnotations.java b/java/java-tests/testData/refactoring/extractMethod/MethodAnnotations.java
new file mode 100644 (file)
index 0000000..a210351
--- /dev/null
@@ -0,0 +1,21 @@
+class Test10 {
+  void test() {
+    <selection>new Super() {
+      int get() {
+        return 0;
+      }
+    };</selection>
+
+        new Super() {
+          @Override
+          int get() {
+            return 0;
+          }
+        };
+  }
+}
+class Super {
+  int get() {
+    return 1;
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/extractMethod/MethodAnnotations_after.java b/java/java-tests/testData/refactoring/extractMethod/MethodAnnotations_after.java
new file mode 100644 (file)
index 0000000..1c7baec
--- /dev/null
@@ -0,0 +1,20 @@
+class Test10 {
+  void test() {
+      newMethod();
+
+      newMethod();
+  }
+
+    private void newMethod() {
+        new Super() {
+          int get() {
+            return 0;
+          }
+        };
+    }
+}
+class Super {
+  int get() {
+    return 1;
+  }
+}
\ No newline at end of file
index 874522ec38f77f215a7a26944d75850ccba80a8f..4c6c21761f5592bf440a259e215537f3237149e8 100644 (file)
@@ -18,7 +18,6 @@ package com.intellij.codeInsight;
 
 import com.intellij.openapi.application.ex.PathManagerEx;
 import com.intellij.openapi.module.Module;
-import com.intellij.openapi.roots.ModifiableRootModel;
 import com.intellij.openapi.roots.ModuleRootModificationUtil;
 import com.intellij.openapi.vfs.VfsUtilCore;
 import com.intellij.pom.java.LanguageLevel;
@@ -26,7 +25,6 @@ import com.intellij.testFramework.IdeaTestUtil;
 import com.intellij.testFramework.UsefulTestCase;
 import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
 import com.intellij.testFramework.fixtures.*;
-import com.intellij.util.Consumer;
 
 public class MultipleJdksHighlightingTest extends UsefulTestCase {
 
@@ -197,6 +195,16 @@ public class MultipleJdksHighlightingTest extends UsefulTestCase {
     myFixture.checkHighlighting();
   }
 
+  public void testUnrelatedDefaultsFromDifferentJdkVersions() throws Exception {
+    ModuleRootModificationUtil.addDependency(myJava8Module, myJava7Module);
+    myFixture.copyFileToProject("java7/p/I.java");
+    myFixture.copyFileToProject("java8/p/I.java");
+
+    final String testName = getTestName(false);
+    myFixture.configureByFiles("java8/p/" + testName + ".java", "java7/p/" + testName + ".java");
+    myFixture.checkHighlighting();
+  }
+
   private void doTestWithoutLibrary() {
     final String name = getTestName(false);
     myFixture.configureByFiles("java7/p/" + name + ".java", "java8/p/" + name + ".java");
index c53bb0085d8720d9f6588825686fc8d029963362..eb9825dd8c70bd5d80e76691d3859a28fff0c3f0 100644 (file)
@@ -30,8 +30,9 @@ public class DelegateWithDefaultParamValueTest extends LightQuickFixParameterize
 
     if (actionShouldBeAvailable) {
       TemplateState state = TemplateManagerImpl.getTemplateState(getEditor());
-      assert state != null;
-      state.gotoEnd(false);
+      if (state != null) {
+        state.gotoEnd(false);
+      }
     }
   }
 
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RedundantLambdaParameterTypeIntentionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RedundantLambdaParameterTypeIntentionTest.java
deleted file mode 100644 (file)
index 4f85962..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2000-2012 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.codeInsight.daemon.quickFix;
-
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.testFramework.IdeaTestUtil;
-
-public class RedundantLambdaParameterTypeIntentionTest extends LightQuickFixParameterizedTestCase {
-  public void test() throws Exception { doAllTests(); }
-
-  @Override
-  protected String getBasePath() {
-    return "/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType";
-  }
-
-  @Override
-  protected Sdk getProjectJDK() {
-    return IdeaTestUtil.getMockJdk18();
-  }
-}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantLambdaParameterTypeInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantLambdaParameterTypeInspectionTest.java
new file mode 100644 (file)
index 0000000..3e610fc
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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:public void testwww() {}.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInspection.lambda.RedundantLambdaParameterTypeInspection;
+import com.intellij.idea.Bombed;
+import com.intellij.openapi.roots.ModuleRootModificationUtil;
+import com.intellij.testFramework.IdeaTestUtil;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+
+import java.util.Calendar;
+import java.util.List;
+
+public class RedundantLambdaParameterTypeInspectionTest extends LightCodeInsightFixtureTestCase {
+  private RedundantLambdaParameterTypeInspection myInspection = new RedundantLambdaParameterTypeInspection();
+  private String myIntentionName = "Remove redundant types";
+
+  @Override
+  protected String getBasePath() {
+    return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInspection/redundantLambdaParameterType";
+  }
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    ModuleRootModificationUtil.setModuleSdk(myModule, IdeaTestUtil.getMockJdk18());
+    myFixture.enableInspections(myInspection);
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    try {
+      myFixture.disableInspections(myInspection);
+    }
+    finally {
+      super.tearDown();
+    }
+  }
+
+  public void testAssignment() {
+    doTest();
+  }
+
+  public void testAssignmentNoParams() {
+    assertIntentionNotAvailable();
+  }
+
+  public void testAssignmentNoTypes() {
+    assertIntentionNotAvailable();
+  }
+
+  public void testAtVarargPlace() {
+    assertIntentionNotAvailable();
+  }
+
+  public void testCallNoTypeArgs() {
+    assertIntentionNotAvailable();
+  }
+
+  public void testCallNoTypeArgs1() {
+    assertIntentionNotAvailable();
+  }
+
+  public void testCallWithTypeArgs() {
+    doTest();
+  }
+
+  public void testInferredFromOtherArgs() {
+    doTest();
+  }
+
+  public void testNoSelfTypeParam() {
+    doTest();
+  }
+
+  public void testTypeParam() {
+    assertIntentionNotAvailable();
+  }
+
+  @Bombed(month = Calendar.AUGUST, day = 1, user = "Pavel Dolgov")
+  public void testInChain() {
+    doTest();
+  }
+
+  private void doTest() {
+    myFixture.configureByFiles(getTestName(false) + ".java");
+    final IntentionAction singleIntention = myFixture.findSingleIntention(myIntentionName);
+    myFixture.launchAction(singleIntention);
+    myFixture.checkResultByFile(getTestName(false) + ".java", getTestName(false) + "_after.java", true);
+  }
+
+  private void assertIntentionNotAvailable() {
+    myFixture.configureByFiles(getTestName(false) + ".java");
+    final List<IntentionAction> intentionActions = myFixture.filterAvailableIntentions(myIntentionName);
+    assertEmpty(myIntentionName + " is not expected", intentionActions);
+  }
+}
\ No newline at end of file
index 37ea37f6c233e42d2549368fb8782c104607d619..b9d84f386d96fe7b251200a0e2e23c98625d5137 100644 (file)
@@ -58,10 +58,7 @@ import org.junit.Assert;
 
 import java.io.IOException;
 import java.lang.ref.SoftReference;
-import java.util.Collections;
-import java.util.List;
-import java.util.Random;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 @PlatformTestCase.WrapInCommand
@@ -915,4 +912,20 @@ public class SmartPsiElementPointersTest extends CodeInsightTestCase {
     assertEquals(psiClass.getNameIdentifier().getTextRange(), TextRange.create(range));
   }
 
+  public void testManySmartPointersCreationDeletionPerformance() throws Exception {
+    String text = StringUtil.repeatSymbol(' ', 100000);
+    PsiFile file = createFile("a.txt", text);
+
+    PlatformTestUtil.startPerformanceTest("", 2000, () -> {
+      List<SmartPsiFileRange> pointers = new ArrayList<>();
+      for (int i = 0; i < text.length() - 1; i++) {
+        pointers.add(getPointerManager().createSmartPsiFileRangePointer(file, new TextRange(i, i + 1)));
+      }
+      Collections.shuffle(pointers);
+      for (SmartPsiFileRange pointer : pointers) {
+        getPointerManager().removePointer(pointer);
+      }
+    }).cpuBound().assertTiming();
+  }
+
 }
index bfe820f7197f1e46ebff06e023cf98b56ff4265d..a84f0d143dabc3ecbed9b034891da79fed0e7c56 100644 (file)
@@ -805,6 +805,18 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
     doTest();
   }
 
+  public void testLocalVariableModifierList() throws Exception {
+    doTest();
+  }
+
+  public void testLocalVariableAnnotationsOrder()  throws Exception {
+    doTest();
+  }
+
+  public void testMethodAnnotations() throws Exception {
+    doTest();
+  }
+
   public void testQualifyWhenConflictingNamePresent() throws Exception {
     final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject());
     settings.ELSE_ON_NEW_LINE = true;
index 45fb4110211bec4eafb7df31796499da49a8f227..d369c892d2ef59f1b229f0672446e02a56a3bcec 100644 (file)
  */
 package com.intellij.psi.tree;
 
-import com.intellij.lang.ASTNode;
 import com.intellij.lang.Language;
-import com.intellij.util.CharTable;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public abstract class CustomParsingType extends IElementType {
+public abstract class CustomParsingType extends IElementType implements ICustomParsingType {
   public CustomParsingType(@NotNull @NonNls String debugName, @Nullable Language language) {
     super(debugName, language);
   }
-
-  public abstract ASTNode parse(CharSequence text, CharTable table);
 }
similarity index 58%
rename from java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RemoveRedundantElseActionTest.java
rename to platform/core-api/src/com/intellij/psi/tree/ICustomParsingType.java
index 0a33ada748f8294716b2f52505464f31e88a8aa4..659f24e4c1693895edec74a73ddadce97fc0dabf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2010 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.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.daemon.quickFix;
+package com.intellij.psi.tree;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.util.CharTable;
+import org.jetbrains.annotations.NotNull;
 
 /**
- * User: anna
- * Date: Aug 30, 2010
+ * A token which is more convenient to parse separately. Parsing is done when leaf elements are created.
  */
-public class RemoveRedundantElseActionTest extends LightQuickFixParameterizedTestCase {
-
-  public void test() throws Exception { doAllTests(); }
-
-  @Override
-  protected String getBasePath() {
-    return "/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse";
-  }
+public interface ICustomParsingType {
 
+  @NotNull
+  ASTNode parse(@NotNull CharSequence text, @NotNull CharTable table);
 }
-
index a07f110329e358f5d7a40323d5c058e21b27bc7a..0563e613ea6131b8fe8aade185589d862ffe3f9b 100644 (file)
@@ -1562,7 +1562,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
         }
 
         if (oldNode.getElementType() instanceof ILazyParseableElementType && type instanceof ILazyParseableElementType ||
-            oldNode.getElementType() instanceof CustomParsingType && type instanceof CustomParsingType) {
+            oldNode.getElementType() instanceof ICustomParsingType && type instanceof ICustomParsingType) {
           return ((TreeElement)oldNode).textMatches(token.getText())
                  ? ThreeState.YES
                  : ThreeState.NO;
@@ -1853,8 +1853,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
       return new PsiWhiteSpaceImpl(text);
     }
 
-    if (type instanceof CustomParsingType) {
-      return (TreeElement)((CustomParsingType)type).parse(text, myCharTable);
+    if (type instanceof ICustomParsingType) {
+      return (TreeElement)((ICustomParsingType)type).parse(text, myCharTable);
     }
 
     if (type instanceof ILazyParseableElementType) {
index d18fb3ed192cf2c0f178c1ae59f5717495f6f53b..28a99999203e89e1163b33b5f2181e151c252386 100644 (file)
@@ -29,7 +29,7 @@ import com.intellij.psi.*;
 import com.intellij.psi.impl.PsiDocumentManagerBase;
 import com.intellij.psi.util.PsiUtilCore;
 import com.intellij.reference.SoftReference;
-import com.intellij.util.ArrayUtil;
+import com.intellij.util.CommonProcessors;
 import com.intellij.util.Processor;
 import com.intellij.util.containers.ContainerUtil;
 import org.jetbrains.annotations.NotNull;
@@ -68,7 +68,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
 
       FilePointersList pointers = reference.file.getUserData(reference.key);
       if (pointers != null) {
-        pointers.remove(reference);
+        pointers.removeReference(reference);
       }
     }
   }
@@ -160,12 +160,13 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
     SmartPointerElementInfo info = pointer.getElementInfo();
     if (!(info instanceof SelfElementInfo)) return;
 
+    PointerReference reference = new PointerReference(pointer, containingFile, POINTERS_KEY);
     while (true) {
       FilePointersList pointers = getPointers(containingFile);
       if (pointers == null) {
         pointers = containingFile.putUserDataIfAbsent(POINTERS_KEY, new FilePointersList());
       }
-      if (pointers.add(new PointerReference(pointer, containingFile, ourQueue, POINTERS_KEY))) {
+      if (pointers.add(reference)) {
         if (((SelfElementInfo)info).hasRange()) {
           pointers.markerCache.rangeChanged();
         }
@@ -193,8 +194,10 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
       if (containingFile == null) return;
       VirtualFile vFile = containingFile.getViewProvider().getVirtualFile();
       FilePointersList pointers = getPointers(vFile);
-      if (pointers == null) return;
-      pointers.remove(pointer);
+      PointerReference reference = ((SmartPsiElementPointerImpl)pointer).pointerReference;
+      if (pointers != null && reference != null) {
+        pointers.removeReference(reference);
+      }
     }
   }
 
@@ -264,17 +267,18 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
     return myPsiDocManager;
   }
 
-  private static class PointerReference extends WeakReference<SmartPsiElementPointerImpl> {
+  static class PointerReference extends WeakReference<SmartPsiElementPointerImpl> {
     @NotNull private final VirtualFile file;
     @NotNull private final Key<FilePointersList> key;
+    private int index = -2;
 
     private PointerReference(@NotNull SmartPsiElementPointerImpl<?> pointer,
                              @NotNull VirtualFile containingFile,
-                             @NotNull ReferenceQueue<SmartPsiElementPointerImpl> queue,
                              @NotNull Key<FilePointersList> key) {
-      super(pointer, queue);
+      super(pointer, ourQueue);
       file = containingFile;
       this.key = key;
+      pointer.pointerReference = this;
     }
   }
 
@@ -292,104 +296,98 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
       }
 
       if (nextAvailableIndex >= references.length || nextAvailableIndex > size*2) {  // overflow or too many dead refs
-        int newCapacity = nextAvailableIndex >= references.length ? references.length * 3/2 +1 : size * 3/2+1;
-        PointerReference[] newReferences = new PointerReference[newCapacity];
+        int newCapacity = (nextAvailableIndex >= references.length ? references.length : size) * 3 / 2 + 1;
+        final PointerReference[] newReferences = new PointerReference[newCapacity];
 
-        int o = 0;
-        for (PointerReference oldRef : references) {
-          if (SoftReference.dereference(oldRef) != null) {
-            newReferences[o++] = oldRef;
+        final int[] o = {0};
+        processAlivePointers(new Processor<SmartPsiElementPointerImpl>() {
+          @Override
+          public boolean process(SmartPsiElementPointerImpl pointer) {
+            storePointerReference(newReferences, o[0]++, pointer.pointerReference);
+            return true;
           }
-        }
+        });
         references = newReferences;
-        size = nextAvailableIndex = o;
+        size = nextAvailableIndex = o[0];
       }
-      references[nextAvailableIndex++] = reference;
+      assert references[nextAvailableIndex] == null : references[nextAvailableIndex];
+      storePointerReference(references, nextAvailableIndex++, reference);
       size++;
       mySorted = false;
       return true;
     }
 
-    private synchronized void remove(@NotNull PointerReference reference) {
-      int index = ArrayUtil.indexOf(references, reference, 0, nextAvailableIndex);
-      if (index != -1) {
-        removeReference(reference, index);
-      }
-    }
-
-    private synchronized void remove(@NotNull SmartPsiElementPointer smartPointer) {
-      for (int i = 0; i < nextAvailableIndex; i++) {
-        PointerReference reference = references[i];
-        if (reference != null && reference.get() == smartPointer) {
-          removeReference(reference, i);
-          return;
-        }
-      }
-    }
+    private synchronized void removeReference(@NotNull PointerReference reference) {
+      int index = reference.index;
+      if (index < 0) return;
 
-    private void removeReference(@NotNull PointerReference reference, int index) {
+      assert references[index] == reference : "At " + index + " expected " + reference + ", found " + references[index];
+      references[index].index = -1;
       references[index] = null;
       if (--size == 0) {
         reference.file.replace(reference.key, this, null);
       }
     }
 
-    boolean processAlivePointers(@NotNull Processor<SmartPsiElementPointerImpl> processor) {
+    synchronized boolean processAlivePointers(@NotNull Processor<SmartPsiElementPointerImpl> processor) {
       for (int i = 0; i < nextAvailableIndex; i++) {
-        SmartPsiElementPointerImpl pointer = SoftReference.dereference(references[i]);
-        if (pointer != null && !processor.process(pointer)) {
+        PointerReference ref = references[i];
+        if (ref == null) continue;
+
+        SmartPsiElementPointerImpl pointer = ref.get();
+        if (pointer == null) {
+          removeReference(ref);
+          continue;
+        }
+
+        if (!processor.process(pointer)) {
           return false;
         }
       }
       return true;
     }
 
-    synchronized List<SelfElementInfo> getSortedInfos() {
+    private void ensureSorted() {
       if (!mySorted) {
-        List<SmartPsiElementPointerImpl> hardRefs = ContainerUtil.newArrayListWithCapacity(size);
-        for (int i = 0; i < nextAvailableIndex; i++) {
-          PointerReference reference = references[i];
-          if (reference == null) continue;
-
-          SmartPsiElementPointerImpl pointer = reference.get();
-          if (pointer != null) {
-            hardRefs.add(pointer);
-          }
-          else {
-            removeReference(reference, i);
-            if (size == 0) {
-              return Collections.emptyList();
-            }
-          }
-        }
-        assert size == hardRefs.size();
+        List<SmartPsiElementPointerImpl> pointers = new ArrayList<SmartPsiElementPointerImpl>();
+        processAlivePointers(new CommonProcessors.CollectProcessor<SmartPsiElementPointerImpl>(pointers));
+        assert size == pointers.size();
 
-        Arrays.sort(references, 0, nextAvailableIndex, new Comparator<PointerReference>() {
+        Collections.sort(pointers, new Comparator<SmartPsiElementPointerImpl>() {
           @Override
-          public int compare(PointerReference o1, PointerReference o2) {
-            SmartPsiElementPointerImpl p1 = SoftReference.dereference(o1);
-            SmartPsiElementPointerImpl p2 = SoftReference.dereference(o2);
-            if (p1 == null || p2 == null) {
-              return p1 != null ? -1 : p2 != null ? 1 : 0; // null references to the end
-            }
+          public int compare(SmartPsiElementPointerImpl p1, SmartPsiElementPointerImpl p2) {
             return MarkerCache.INFO_COMPARATOR.compare((SelfElementInfo)p1.getElementInfo(), (SelfElementInfo)p2.getElementInfo());
           }
         });
-        nextAvailableIndex = hardRefs.size();
+
+        for (int i = 0; i < pointers.size(); i++) {
+          storePointerReference(references, i, pointers.get(i).pointerReference);
+        }
+        Arrays.fill(references, pointers.size(), nextAvailableIndex, null);
+        nextAvailableIndex = pointers.size();
         mySorted = true;
       }
+    }
 
-      List<SelfElementInfo> infos = ContainerUtil.newArrayListWithCapacity(size);
-      for (int i = 0; i < nextAvailableIndex; i++) {
-        Reference<SmartPsiElementPointerImpl> reference = references[i];
-        SmartPsiElementPointerImpl pointer = SoftReference.dereference(reference);
-        if (pointer != null) {
+    private static void storePointerReference(PointerReference[] references, int index, PointerReference ref) {
+      references[index] = ref;
+      ref.index = index;
+    }
+
+    synchronized List<SelfElementInfo> getSortedInfos() {
+      ensureSorted();
+
+      final List<SelfElementInfo> infos = ContainerUtil.newArrayListWithCapacity(size);
+      processAlivePointers(new Processor<SmartPsiElementPointerImpl>() {
+        @Override
+        public boolean process(SmartPsiElementPointerImpl pointer) {
           SelfElementInfo info = (SelfElementInfo)pointer.getElementInfo();
-          if (!info.hasRange()) break;
+          if (!info.hasRange()) return false;
 
           infos.add(info);
+          return true;
         }
-      }
+      });
       return infos;
     }
 
index ee7c4c9c249a6acc8a1268892f23d2d27555fb40..01e43e3b8d3576b0b9d305ae341134e984d3f013 100644 (file)
@@ -46,6 +46,7 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
   private final SmartPointerElementInfo myElementInfo;
   private final Class<? extends PsiElement> myElementClass;
   private byte myReferenceCount = 1;
+  @Nullable SmartPointerManagerImpl.PointerReference pointerReference;
 
   SmartPsiElementPointerImpl(@NotNull Project project, @NotNull E element, @Nullable PsiFile containingFile, boolean forInjected) {
     this(element, createElementInfo(project, element, containingFile, forInjected), element.getClass());
index cd0915a0d435da6d14abbd2612b5cf586125f9b5..30f8a8f7d35eb547a44cca9475564ae392227077 100644 (file)
@@ -17,6 +17,7 @@ package com.intellij.diff.comparison;
 
 import com.intellij.diff.fragments.DiffFragment;
 import com.intellij.diff.fragments.LineFragment;
+import com.intellij.diff.fragments.MergeLineFragment;
 import com.intellij.openapi.components.ServiceManager;
 import com.intellij.openapi.progress.ProgressIndicator;
 import org.jetbrains.annotations.NotNull;
@@ -61,6 +62,16 @@ public abstract class ComparisonManager {
                                                        @NotNull ComparisonPolicy policy,
                                                        @NotNull ProgressIndicator indicator) throws DiffTooBigException;
 
+  /**
+   * Compare three texts by-line (LEFT - BASE - RIGHT)
+   */
+  @NotNull
+  public abstract List<MergeLineFragment> compareLines(@NotNull CharSequence text1,
+                                                       @NotNull CharSequence text2,
+                                                       @NotNull CharSequence text3,
+                                                       @NotNull ComparisonPolicy policy,
+                                                       @NotNull ProgressIndicator indicator) throws DiffTooBigException;
+
   /**
    * Compare two texts by-word
    */
index f204eafde823ef804767dae768fcfdb50c232a73..ae75bbaf8f33a201d87dfffadf6bc981e444e0ce 100644 (file)
  */
 package com.intellij.diff.comparison;
 
-import com.intellij.diff.comparison.iterables.DiffIterableUtil.*;
+import com.intellij.diff.comparison.iterables.DiffIterableUtil.ExpandChangeBuilder;
 import com.intellij.diff.comparison.iterables.FairDiffIterable;
-import com.intellij.diff.fragments.LineFragment;
-import com.intellij.diff.fragments.LineFragmentImpl;
-import com.intellij.diff.fragments.MergeLineFragment;
-import com.intellij.diff.fragments.MergeLineFragmentImpl;
-import com.intellij.diff.util.IntPair;
 import com.intellij.diff.util.MergeRange;
 import com.intellij.diff.util.Range;
 import com.intellij.openapi.progress.ProgressIndicator;
@@ -29,68 +24,77 @@ import com.intellij.openapi.util.Pair;
 import com.intellij.openapi.util.registry.Registry;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.util.containers.ContainerUtil;
+import gnu.trove.Equality;
 import gnu.trove.TIntArrayList;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import static com.intellij.diff.comparison.ComparisonPolicy.IGNORE_WHITESPACES;
 import static com.intellij.diff.comparison.TrimUtil.trimEnd;
 import static com.intellij.diff.comparison.TrimUtil.trimStart;
-import static com.intellij.diff.comparison.iterables.DiffIterableUtil.*;
+import static com.intellij.diff.comparison.iterables.DiffIterableUtil.diff;
+import static com.intellij.diff.comparison.iterables.DiffIterableUtil.fair;
 import static com.intellij.openapi.util.text.StringUtil.isWhiteSpace;
 
 public class ByLine {
   @NotNull
-  public static List<LineFragment> compare(@NotNull CharSequence text1,
-                                           @NotNull CharSequence text2,
-                                           @NotNull ComparisonPolicy policy,
-                                           @NotNull ProgressIndicator indicator) {
+  public static FairDiffIterable compare(@NotNull List<? extends CharSequence> lines1,
+                                         @NotNull List<? extends CharSequence> lines2,
+                                         @NotNull ComparisonPolicy policy,
+                                         @NotNull ProgressIndicator indicator) {
     indicator.checkCanceled();
-
-    List<Line> lines1 = getLines(text1, policy);
-    List<Line> lines2 = getLines(text2, policy);
-
-    FairDiffIterable changes = compareSmart(lines1, lines2, indicator);
-    changes = optimizeLineChunks(lines1, lines2, changes, indicator);
-    changes = expandRanges(lines1, lines2, changes, indicator);
-    return convertIntoFragments(lines1, lines2, changes);
+    return doCompare(getLines(lines1, policy), getLines(lines2, policy), policy, indicator);
   }
 
   @NotNull
-  public static List<LineFragment> compareTwoStep(@NotNull CharSequence text1,
-                                                  @NotNull CharSequence text2,
-                                                  @NotNull ComparisonPolicy policy,
-                                                  @NotNull ProgressIndicator indicator) {
+  public static List<MergeRange> compare(@NotNull List<? extends CharSequence> lines1,
+                                         @NotNull List<? extends CharSequence> lines2,
+                                         @NotNull List<? extends CharSequence> lines3,
+                                         @NotNull ComparisonPolicy policy,
+                                         @NotNull ProgressIndicator indicator) {
     indicator.checkCanceled();
+    return doCompare(getLines(lines1, policy), getLines(lines2, policy), getLines(lines3, policy), policy, indicator);
+  }
+
+  //
+  // Impl
+  //
 
-    List<Line> lines1 = getLines(text1, policy);
-    List<Line> lines2 = getLines(text2, policy);
+  @NotNull
+  static FairDiffIterable doCompare(@NotNull List<Line> lines1,
+                                    @NotNull List<Line> lines2,
+                                    @NotNull ComparisonPolicy policy,
+                                    @NotNull ProgressIndicator indicator) {
+    indicator.checkCanceled();
 
-    List<Line> iwLines1 = convertToIgnoreWhitespace(lines1);
-    List<Line> iwLines2 = convertToIgnoreWhitespace(lines2);
+    if (policy == IGNORE_WHITESPACES) {
+      FairDiffIterable changes = compareSmart(lines1, lines2, indicator);
+      changes = optimizeLineChunks(lines1, lines2, changes, indicator);
+      return correctChangesSecondStepIW(lines1, lines2, changes);
+    }
+    else {
+      List<Line> iwLines1 = convertMode(lines1, IGNORE_WHITESPACES);
+      List<Line> iwLines2 = convertMode(lines2, IGNORE_WHITESPACES);
 
-    FairDiffIterable iwChanges = compareSmart(iwLines1, iwLines2, indicator);
-    iwChanges = optimizeLineChunks(lines1, lines2, iwChanges, indicator);
-    FairDiffIterable changes = correctChangesSecondStep(lines1, lines2, iwChanges);
-    return convertIntoFragments(lines1, lines2, changes);
+      FairDiffIterable iwChanges = compareSmart(iwLines1, iwLines2, indicator);
+      iwChanges = optimizeLineChunks(lines1, lines2, iwChanges, indicator);
+      return correctChangesSecondStep(lines1, lines2, iwChanges);
+    }
   }
 
   @NotNull
-  public static List<MergeLineFragment> compareTwoStep(@NotNull CharSequence text1,
-                                                       @NotNull CharSequence text2,
-                                                       @NotNull CharSequence text3,
-                                                       @NotNull ComparisonPolicy policy,
-                                                       @NotNull ProgressIndicator indicator) {
+  static List<MergeRange> doCompare(@NotNull List<Line> lines1,
+                                    @NotNull List<Line> lines2,
+                                    @NotNull List<Line> lines3,
+                                    @NotNull ComparisonPolicy policy,
+                                    @NotNull ProgressIndicator indicator) {
     indicator.checkCanceled();
 
-    List<Line> lines1 = getLines(text1, policy);
-    List<Line> lines2 = getLines(text2, policy);
-    List<Line> lines3 = getLines(text3, policy);
-
-    List<Line> iwLines1 = convertToIgnoreWhitespace(lines1);
-    List<Line> iwLines2 = convertToIgnoreWhitespace(lines2);
-    List<Line> iwLines3 = convertToIgnoreWhitespace(lines3);
+    List<Line> iwLines1 = convertMode(lines1, IGNORE_WHITESPACES);
+    List<Line> iwLines2 = convertMode(lines2, IGNORE_WHITESPACES);
+    List<Line> iwLines3 = convertMode(lines3, IGNORE_WHITESPACES);
 
     FairDiffIterable iwChanges1 = compareSmart(iwLines2, iwLines1, indicator);
     iwChanges1 = optimizeLineChunks(lines2, lines1, iwChanges1, indicator);
@@ -100,18 +104,30 @@ public class ByLine {
     iwChanges2 = optimizeLineChunks(lines2, lines3, iwChanges2, indicator);
     FairDiffIterable iterable2 = correctChangesSecondStep(lines2, lines3, iwChanges2);
 
-    List<MergeRange> conflicts = ComparisonMergeUtil.buildFair(iterable1, iterable2, indicator);
-    return convertIntoFragments(conflicts);
+    return ComparisonMergeUtil.buildFair(iterable1, iterable2, indicator);
   }
 
-  //
-  // Impl
-  //
-
   @NotNull
   private static FairDiffIterable correctChangesSecondStep(@NotNull final List<Line> lines1,
                                                            @NotNull final List<Line> lines2,
                                                            @NotNull final FairDiffIterable changes) {
+    return doCorrectChangesSecondStep(lines1, lines2, changes,
+                                      Equality.CANONICAL);
+  }
+
+  @NotNull
+  private static FairDiffIterable correctChangesSecondStepIW(@NotNull final List<Line> lines1,
+                                                             @NotNull final List<Line> lines2,
+                                                             @NotNull final FairDiffIterable changes) {
+    return doCorrectChangesSecondStep(lines1, lines2, changes,
+                                      (l1, l2) -> StringUtil.equals(l1.getContent(), l2.getContent()));
+  }
+
+  @NotNull
+  private static FairDiffIterable doCorrectChangesSecondStep(@NotNull final List<Line> lines1,
+                                                             @NotNull final List<Line> lines2,
+                                                             @NotNull final FairDiffIterable changes,
+                                                             @NotNull final Equality<Line> maximisingEquality) {
     /*
      * We want to fix invalid matching here:
      *
@@ -156,7 +172,7 @@ public class ByLine {
             Line line2 = lines2.get(index2);
 
             if (!StringUtil.equalsIgnoreWhitespaces(sample, line1.getContent())) {
-              if (line1.equals(line2)) {
+              if (maximisingEquality.equals(line1, line2)) {
                 flush(index1, index2);
                 builder.markEqual(index1, index2);
               }
@@ -197,13 +213,24 @@ public class ByLine {
       }
 
       private void alignExactMatching(TIntArrayList subLines1, TIntArrayList subLines2) {
-        if (subLines1.size() == subLines2.size()) return;
-
         int n = Math.max(subLines1.size(), subLines2.size());
-        if (n > 10) return; // we use brute-force algorithm (C_n_k). This will limit search space by ~250 cases.
+        boolean skipAligning = n > 10 || // we use brute-force algorithm (C_n_k). This will limit search space by ~250 cases.
+                               subLines1.size() == subLines2.size(); // nothing to do
+
+        if (skipAligning) {
+          int count = Math.min(subLines1.size(), subLines2.size());
+          for (int i = 0; i < count; i++) {
+            int index1 = subLines1.get(i);
+            int index2 = subLines2.get(i);
+            if (lines1.get(index1).equals(lines2.get(index2))) {
+              builder.markEqual(index1, index2);
+            }
+          }
+          return;
+        }
 
         if (subLines1.size() < subLines2.size()) {
-          int[] matching = getBestMatchingAlignment(subLines1, subLines2, lines1, lines2);
+          int[] matching = getBestMatchingAlignment(subLines1, subLines2, lines1, lines2, maximisingEquality);
           for (int i = 0; i < subLines1.size(); i++) {
             int index1 = subLines1.get(i);
             int index2 = subLines2.get(matching[i]);
@@ -213,7 +240,7 @@ public class ByLine {
           }
         }
         else {
-          int[] matching = getBestMatchingAlignment(subLines2, subLines1, lines2, lines1);
+          int[] matching = getBestMatchingAlignment(subLines2, subLines1, lines2, lines1, maximisingEquality);
           for (int i = 0; i < subLines2.size(); i++) {
             int index1 = subLines1.get(matching[i]);
             int index2 = subLines2.get(i);
@@ -232,7 +259,8 @@ public class ByLine {
   private static int[] getBestMatchingAlignment(@NotNull final TIntArrayList subLines1,
                                                 @NotNull final TIntArrayList subLines2,
                                                 @NotNull final List<Line> lines1,
-                                                @NotNull final List<Line> lines2) {
+                                                @NotNull final List<Line> lines2,
+                                                @NotNull final Equality<Line> maximisingEquality) {
     assert subLines1.size() < subLines2.size();
     final int size = subLines1.size();
 
@@ -267,7 +295,7 @@ public class ByLine {
         for (int i = 0; i < size; i++) {
           int index1 = subLines1.get(i);
           int index2 = subLines2.get(comb[i]);
-          if (lines1.get(index1).equals(lines2.get(index2))) weight++;
+          if (maximisingEquality.equals(lines1.get(index1), lines2.get(index2))) weight++;
         }
 
         if (weight > bestWeight) {
@@ -288,45 +316,6 @@ public class ByLine {
     return new ChunkOptimizer.LineChunkOptimizer(lines1, lines2, iterable, indicator).build();
   }
 
-  @NotNull
-  private static List<LineFragment> convertIntoFragments(@NotNull List<Line> lines1,
-                                                         @NotNull List<Line> lines2,
-                                                         @NotNull FairDiffIterable changes) {
-    List<LineFragment> fragments = new ArrayList<>();
-    for (Range ch : changes.iterateChanges()) {
-      IntPair offsets1 = getOffsets(lines1, ch.start1, ch.end1);
-      IntPair offsets2 = getOffsets(lines2, ch.start2, ch.end2);
-
-      fragments.add(new LineFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2,
-                                         offsets1.val1, offsets1.val2, offsets2.val1, offsets2.val2));
-    }
-    return fragments;
-  }
-
-  @NotNull
-  private static List<MergeLineFragment> convertIntoFragments(@NotNull List<MergeRange> conflicts) {
-    return ContainerUtil.map(conflicts, ch -> new MergeLineFragmentImpl(ch));
-  }
-
-  @NotNull
-  private static IntPair getOffsets(@NotNull List<Line> lines, int startIndex, int endIndex) {
-    if (startIndex == endIndex) {
-      int offset;
-      if (startIndex < lines.size()) {
-        offset = lines.get(startIndex).getOffset1();
-      }
-      else {
-        offset = lines.get(lines.size() - 1).getOffset2();
-      }
-      return new IntPair(offset, offset);
-    }
-    else {
-      int offset1 = lines.get(startIndex).getOffset1();
-      int offset2 = lines.get(endIndex - 1).getOffset2();
-      return new IntPair(offset1, offset2);
-    }
-  }
-
   /*
    * Compare lines in two steps:
    *  - compare ignoring "unimportant" lines
@@ -361,90 +350,44 @@ public class ByLine {
     return Pair.create(bigLines, indexes);
   }
 
-  @NotNull
-  private static FairDiffIterable expandRanges(@NotNull List<Line> lines1,
-                                               @NotNull List<Line> lines2,
-                                               @NotNull FairDiffIterable iterable,
-                                               @NotNull ProgressIndicator indicator) {
-    List<Range> changes = new ArrayList<>();
-
-    for (Range ch : iterable.iterateChanges()) {
-      Range expanded = TrimUtil.expand(lines1, lines2, ch.start1, ch.start2, ch.end1, ch.end2);
-      if (!expanded.isEmpty()) changes.add(expanded);
-    }
-
-    return fair(create(changes, lines1.size(), lines2.size()));
-  }
-
   //
   // Lines
   //
 
   @NotNull
-  private static List<Line> getLines(@NotNull CharSequence text, @NotNull ComparisonPolicy policy) {
-    List<Line> lines = new ArrayList<>();
-
-    int offset = 0;
-    while (true) {
-      Line line = createLine(text, offset, policy);
-      lines.add(line);
-      offset = line.getOffset2();
-      if (!line.hasNewline()) break;
-    }
-
-    return lines;
-  }
-
-  @NotNull
-  private static Line createLine(@NotNull CharSequence text, int offset, @NotNull ComparisonPolicy policy) {
-    switch (policy) {
-      case DEFAULT:
-        return Line.createDefault(text, offset);
-      case IGNORE_WHITESPACES:
-        return Line.createIgnore(text, offset);
-      case TRIM_WHITESPACES:
-        return Line.createTrim(text, offset);
-      default:
-        throw new IllegalArgumentException(policy.name());
-    }
+  private static List<Line> getLines(@NotNull List<? extends CharSequence> text, @NotNull ComparisonPolicy policy) {
+    return ContainerUtil.map(text, (line) -> new Line(line, policy));
   }
 
   @NotNull
-  private static List<Line> convertToIgnoreWhitespace(@NotNull List<Line> original) {
+  private static List<Line> convertMode(@NotNull List<Line> original, @NotNull ComparisonPolicy policy) {
     List<Line> result = new ArrayList<>(original.size());
-
     for (Line line : original) {
-      result.add(Line.createIgnore(line.getOriginalText(), line.getOffset1()));
+      result.add(new Line(line.getContent(), policy));
     }
-
     return result;
   }
 
-  static class Line extends TextChunk {
-    enum Mode {DEFAULT, TRIM, IGNORE}
-
-    @NotNull private final Mode myMode;
+  static class Line {
+    @NotNull private final CharSequence myText;
+    @NotNull private final ComparisonPolicy myPolicy;
     private final int myHash;
     private final int myNonSpaceChars;
-    private final boolean myNewline;
-
-    public Line(@NotNull CharSequence text, int offset1, int offset2,
-                @NotNull Mode mode, int hash, int nonSpaceChars, boolean newline) {
-      super(text, offset1, offset2);
-      myMode = mode;
-      myHash = hash;
-      myNonSpaceChars = nonSpaceChars;
-      myNewline = newline;
-    }
 
-    public boolean hasNewline() {
-      return myNewline;
+    public Line(@NotNull CharSequence text, @NotNull ComparisonPolicy policy) {
+      myText = text;
+      myPolicy = policy;
+      myHash = hashCode(text, policy);
+      myNonSpaceChars = countNonSpaceChars(text);
     }
 
     @NotNull
-    @Override
     public CharSequence getContent() {
-      return getOriginalText().subSequence(getOffset1(), getOffset2() - (myNewline ? 1 : 0));
+      return myText;
+    }
+
+    public int getNonSpaceChars() {
+      return myNonSpaceChars;
     }
 
     @Override
@@ -453,20 +396,11 @@ public class ByLine {
       if (o == null || getClass() != o.getClass()) return false;
 
       Line line = (Line)o;
-      assert myMode == line.myMode;
+      assert myPolicy == line.myPolicy;
 
       if (hashCode() != line.hashCode()) return false;
 
-      switch (myMode) {
-        case DEFAULT:
-          return StringUtil.equals(getContent(), line.getContent());
-        case TRIM:
-          return StringUtil.equalsTrimWhitespaces(getContent(), line.getContent());
-        case IGNORE:
-          return StringUtil.equalsIgnoreWhitespaces(getContent(), line.getContent());
-        default:
-          throw new IllegalArgumentException(myMode.toString());
-      }
+      return equals(getContent(), line.getContent(), myPolicy);
     }
 
     @Override
@@ -474,87 +408,47 @@ public class ByLine {
       return myHash;
     }
 
-    public int getNonSpaceChars() {
-      return myNonSpaceChars;
-    }
+    private static int countNonSpaceChars(@NotNull CharSequence text) {
+      int nonSpace = 0;
 
-    public static Line createDefault(@NotNull CharSequence text, int startOffset) {
       int len = text.length();
+      int offset = 0;
 
-      int h = 0;
-      int nonSpace = 0;
-      boolean newline = false;
-
-      int offset = startOffset;
       while (offset < len) {
         char c = text.charAt(offset);
-        if (c == '\n') {
-          offset++;
-          newline = true;
-          break;
-        }
         if (!isWhiteSpace(c)) nonSpace++;
-        h = 31 * h + c;
         offset++;
       }
 
-      return new Line(text, startOffset, offset, Mode.DEFAULT, h, nonSpace, newline);
+      return nonSpace;
     }
 
-    public static Line createIgnore(@NotNull CharSequence text, int startOffset) {
-      int len = text.length();
-
-      int h = 0;
-      int nonSpace = 0;
-      boolean newline = false;
-
-      int offset = startOffset;
-      while (offset < len) {
-        char c = text.charAt(offset);
-        if (c == '\n') {
-          offset++;
-          newline = true;
-          break;
-        }
-        if (!isWhiteSpace(c)) {
-          nonSpace++;
-          h = 31 * h + c;
-        }
-        offset++;
+    private static boolean equals(@NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull ComparisonPolicy policy) {
+      switch (policy) {
+        case DEFAULT:
+          return StringUtil.equals(text1, text2);
+        case TRIM_WHITESPACES:
+          return StringUtil.equalsTrimWhitespaces(text1, text2);
+        case IGNORE_WHITESPACES:
+          return StringUtil.equalsIgnoreWhitespaces(text1, text2);
+        default:
+          throw new IllegalArgumentException(policy.toString());
       }
-
-      return new Line(text, startOffset, offset, Mode.IGNORE, h, nonSpace, newline);
     }
 
-    public static Line createTrim(@NotNull CharSequence text, int startOffset) {
-      int len = text.length();
-
-      int nonSpace = 0;
-      boolean newline = false;
-
-      int offset = startOffset;
-      while (offset < len) {
-        char c = text.charAt(offset);
-        if (c == '\n') {
-          offset++;
-          newline = true;
-          break;
-        }
-        if (!isWhiteSpace(c)) nonSpace++;
-        offset++;
+    private static int hashCode(@NotNull CharSequence text, @NotNull ComparisonPolicy policy) {
+      switch (policy) {
+        case DEFAULT:
+          return StringUtil.stringHashCode(text);
+        case TRIM_WHITESPACES:
+          int offset1 = trimStart(text, 0, text.length());
+          int offset2 = trimEnd(text, offset1, text.length());
+          return StringUtil.stringHashCode(text, offset1, offset2);
+        case IGNORE_WHITESPACES:
+          return StringUtil.stringHashCodeIgnoreWhitespaces(text);
+        default:
+          throw new IllegalArgumentException(policy.name());
       }
-
-      int h = calcTrimHash(text, startOffset, offset);
-
-      return new Line(text, startOffset, offset, Mode.TRIM, h, nonSpace, newline);
-    }
-
-
-    private static int calcTrimHash(@NotNull CharSequence text, int offset1, int offset2) {
-      offset1 = trimStart(text, offset1, offset2);
-      offset2 = trimEnd(text, offset1, offset2);
-
-      return StringUtil.stringHashCode(text, offset1, offset2);
     }
   }
 }
index 7e97f0de823a6374f01c9c4f191001dc1d1ab107..eec26d3f1e25b0cef7caa292447efe883224fd5f 100644 (file)
@@ -17,24 +17,23 @@ package com.intellij.diff.comparison;
 
 import com.intellij.diff.comparison.LineFragmentSplitter.WordBlock;
 import com.intellij.diff.comparison.iterables.DiffIterable;
-import com.intellij.diff.comparison.iterables.DiffIterableUtil;
 import com.intellij.diff.comparison.iterables.DiffIterableUtil.*;
 import com.intellij.diff.comparison.iterables.FairDiffIterable;
 import com.intellij.diff.fragments.DiffFragment;
 import com.intellij.diff.fragments.MergeWordFragment;
-import com.intellij.diff.fragments.MergeWordFragmentImpl;
 import com.intellij.diff.util.MergeRange;
 import com.intellij.diff.util.Range;
 import com.intellij.openapi.progress.ProgressIndicator;
 import com.intellij.openapi.util.Couple;
 import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.text.MergingCharSequence;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import static com.intellij.diff.comparison.ComparisonManagerImpl.convertIntoDiffFragments;
+import static com.intellij.diff.comparison.ComparisonManagerImpl.convertIntoMergeWordFragments;
 import static com.intellij.diff.comparison.TrimUtil.*;
 import static com.intellij.diff.comparison.TrimUtil.trim;
 import static com.intellij.diff.comparison.iterables.DiffIterableUtil.*;
@@ -66,7 +65,7 @@ public class ByWord {
     FairDiffIterable delimitersIterable = matchAdjustmentDelimiters(text1, text2, words1, words2, wordChanges, indicator);
     DiffIterable iterable = matchAdjustmentWhitespaces(text1, text2, delimitersIterable, policy, indicator);
 
-    return convertIntoFragments(iterable);
+    return convertIntoDiffFragments(iterable);
   }
 
   @NotNull
@@ -92,7 +91,7 @@ public class ByWord {
     List<MergeRange> wordConflicts = ComparisonMergeUtil.buildFair(iterable1, iterable2, indicator);
     List<MergeRange> result = matchAdjustmentWhitespaces(text1, text2, text3, wordConflicts, policy, indicator);
 
-    return convertIntoFragments(result);
+    return convertIntoMergeWordFragments(result);
   }
 
   @NotNull
@@ -144,7 +143,7 @@ public class ByWord {
                                                                       offsets.start1, offsets.start2, indicator);
       DiffIterable iterable = matchAdjustmentWhitespaces(subtext1, subtext2, delimitersIterable, policy, indicator);
 
-      List<DiffFragment> fragments = convertIntoFragments(iterable);
+      List<DiffFragment> fragments = convertIntoDiffFragments(iterable);
 
       int newlines1 = countNewlines(subwords1);
       int newlines2 = countNewlines(subwords2);
@@ -159,16 +158,6 @@ public class ByWord {
   // Impl
   //
 
-  @NotNull
-  private static List<MergeWordFragment> convertIntoFragments(@NotNull List<MergeRange> conflicts) {
-    return ContainerUtil.map(conflicts, ch -> new MergeWordFragmentImpl(ch));
-  }
-
-  @NotNull
-  private static List<DiffFragment> convertIntoFragments(@NotNull DiffIterable iterable) {
-    return DiffIterableUtil.convertIntoFragments(iterable);
-  }
-
   @NotNull
   private static FairDiffIterable optimizeWordChunks(@NotNull CharSequence text1,
                                                      @NotNull CharSequence text2,
@@ -863,14 +852,32 @@ public class ByWord {
     int getOffset2();
   }
 
-  static class WordChunk extends TextChunk implements InlineChunk {
+  static class WordChunk implements InlineChunk {
+    @NotNull private final CharSequence myText;
+    private final int myOffset1;
+    private final int myOffset2;
     private final int myHash;
 
     public WordChunk(@NotNull CharSequence text, int offset1, int offset2, int hash) {
-      super(text, offset1, offset2);
+      myText = text;
+      myOffset1 = offset1;
+      myOffset2 = offset2;
       myHash = hash;
     }
 
+    @NotNull
+    public CharSequence getContent() {
+      return myText.subSequence(myOffset1, myOffset2);
+    }
+
+    public int getOffset1() {
+      return myOffset1;
+    }
+
+    public int getOffset2() {
+      return myOffset2;
+    }
+
     @Override
     public boolean equals(Object o) {
       if (this == o) return true;
index 26aa3fa4ed2023e8c70713eb9e58ac2f5235df63..31f67d866a6f2dec8213964424c941cd6528fdac 100644 (file)
  */
 package com.intellij.diff.comparison;
 
-import com.intellij.diff.fragments.DiffFragment;
-import com.intellij.diff.fragments.DiffFragmentImpl;
-import com.intellij.diff.fragments.LineFragment;
-import com.intellij.diff.fragments.LineFragmentImpl;
+import com.intellij.diff.comparison.iterables.DiffIterable;
+import com.intellij.diff.comparison.iterables.FairDiffIterable;
+import com.intellij.diff.fragments.*;
+import com.intellij.diff.util.IntPair;
+import com.intellij.diff.util.MergeRange;
 import com.intellij.diff.util.Range;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.progress.ProgressIndicator;
@@ -33,8 +34,6 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import static com.intellij.diff.comparison.iterables.DiffIterableUtil.convertIntoFragments;
-
 public class ComparisonManagerImpl extends ComparisonManager {
   public static final Logger LOG = Logger.getInstance(ComparisonManagerImpl.class);
 
@@ -44,12 +43,24 @@ public class ComparisonManagerImpl extends ComparisonManager {
                                          @NotNull CharSequence text2,
                                          @NotNull ComparisonPolicy policy,
                                          @NotNull ProgressIndicator indicator) throws DiffTooBigException {
-    if (policy == ComparisonPolicy.IGNORE_WHITESPACES) {
-      return ByLine.compare(text1, text2, policy, indicator);
-    }
-    else {
-      return ByLine.compareTwoStep(text1, text2, policy, indicator);
-    }
+    List<Line> lines1 = getLines(text1);
+    List<Line> lines2 = getLines(text2);
+    FairDiffIterable iterable = ByLine.compare(lines1, lines2, policy, indicator);
+    return convertIntoLineFragments(lines1, lines2, iterable);
+  }
+
+  @NotNull
+  @Override
+  public List<MergeLineFragment> compareLines(@NotNull CharSequence text1,
+                                              @NotNull CharSequence text2,
+                                              @NotNull CharSequence text3,
+                                              @NotNull ComparisonPolicy policy,
+                                              @NotNull ProgressIndicator indicator) throws DiffTooBigException {
+    List<Line> lines1 = getLines(text1);
+    List<Line> lines2 = getLines(text2);
+    List<Line> lines3 = getLines(text3);
+    List<MergeRange> ranges = ByLine.compare(lines1, lines2, lines3, policy, indicator);
+    return convertIntoMergeLineFragments(ranges);
   }
 
   @NotNull
@@ -145,13 +156,13 @@ public class ComparisonManagerImpl extends ComparisonManager {
                                          @NotNull ComparisonPolicy policy,
                                          @NotNull ProgressIndicator indicator) throws DiffTooBigException {
     if (policy == ComparisonPolicy.IGNORE_WHITESPACES) {
-      return convertIntoFragments(ByChar.compareIgnoreWhitespaces(text1, text2, indicator));
+      return convertIntoDiffFragments(ByChar.compareIgnoreWhitespaces(text1, text2, indicator));
     }
     if (policy == ComparisonPolicy.DEFAULT) {
-      return convertIntoFragments(ByChar.compareTwoStep(text1, text2, indicator));
+      return convertIntoDiffFragments(ByChar.compareTwoStep(text1, text2, indicator));
     }
     LOG.warn(policy.toString() + " is not supported by ByChar comparison");
-    return convertIntoFragments(ByChar.compareTwoStep(text1, text2, indicator));
+    return convertIntoDiffFragments(ByChar.compareTwoStep(text1, text2, indicator));
   }
 
   @Override
@@ -159,6 +170,63 @@ public class ComparisonManagerImpl extends ComparisonManager {
     return ComparisonUtil.isEquals(text1, text2, policy);
   }
 
+  //
+  // Fragments
+  //
+
+  @NotNull
+  public static List<DiffFragment> convertIntoDiffFragments(@NotNull DiffIterable changes) {
+    final List<DiffFragment> fragments = new ArrayList<>();
+    for (Range ch : changes.iterateChanges()) {
+      fragments.add(new DiffFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2));
+    }
+    return fragments;
+  }
+
+  @NotNull
+  public static List<LineFragment> convertIntoLineFragments(@NotNull List<Line> lines1,
+                                                            @NotNull List<Line> lines2,
+                                                            @NotNull FairDiffIterable changes) {
+    List<LineFragment> fragments = new ArrayList<>();
+    for (Range ch : changes.iterateChanges()) {
+      IntPair offsets1 = getOffsets(lines1, ch.start1, ch.end1);
+      IntPair offsets2 = getOffsets(lines2, ch.start2, ch.end2);
+
+      fragments.add(new LineFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2,
+                                         offsets1.val1, offsets1.val2, offsets2.val1, offsets2.val2));
+    }
+    return fragments;
+  }
+
+  @NotNull
+  private static IntPair getOffsets(@NotNull List<Line> lines, int startIndex, int endIndex) {
+    if (startIndex == endIndex) {
+      int offset;
+      if (startIndex < lines.size()) {
+        offset = lines.get(startIndex).getOffset1();
+      }
+      else {
+        offset = lines.get(lines.size() - 1).getOffset2();
+      }
+      return new IntPair(offset, offset);
+    }
+    else {
+      int offset1 = lines.get(startIndex).getOffset1();
+      int offset2 = lines.get(endIndex - 1).getOffset2();
+      return new IntPair(offset1, offset2);
+    }
+  }
+
+  @NotNull
+  public static List<MergeLineFragment> convertIntoMergeLineFragments(@NotNull List<MergeRange> conflicts) {
+    return ContainerUtil.map(conflicts, ch -> new MergeLineFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2, ch.start3, ch.end3));
+  }
+
+  @NotNull
+  public static List<MergeWordFragment> convertIntoMergeWordFragments(@NotNull List<MergeRange> conflicts) {
+    return ContainerUtil.map(conflicts, ch -> new MergeWordFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2, ch.start3, ch.end3));
+  }
+
   //
   // Post process line fragments
   //
@@ -304,4 +372,45 @@ public class ComparisonManagerImpl extends ComparisonManager {
     int length2 = lineFragment.getEndOffset2() - lineFragment.getStartOffset2();
     return Collections.singletonList(new DiffFragmentImpl(0, length1, 0, length2));
   }
+
+  @NotNull
+  private static List<Line> getLines(@NotNull CharSequence text) {
+    List<Line> lines = new ArrayList<>();
+
+    int offset = 0;
+    while (true) {
+      int lineEnd = StringUtil.indexOf(text, '\n', offset);
+      if (lineEnd != -1) {
+        lines.add(new Line(text, offset, lineEnd, true));
+        offset = lineEnd + 1;
+      }
+      else {
+        lines.add(new Line(text, offset, text.length(), false));
+        break;
+      }
+    }
+
+    return lines;
+  }
+
+  private static class Line extends CharSequenceSubSequence {
+    private final int myOffset1;
+    private final int myOffset2;
+    private final boolean myNewline;
+
+    public Line(@NotNull CharSequence chars, int offset1, int offset2, boolean newline) {
+      super(chars, offset1, offset2);
+      myOffset1 = offset1;
+      myOffset2 = offset2;
+      myNewline = newline;
+    }
+
+    public int getOffset1() {
+      return myOffset1;
+    }
+
+    public int getOffset2() {
+      return myOffset2 + (myNewline ? 1 : 0);
+    }
+  }
 }
diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/TextChunk.java b/platform/diff-impl/src/com/intellij/diff/comparison/TextChunk.java
deleted file mode 100644 (file)
index 8a163f3..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2000-2015 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.diff.comparison;
-
-import org.jetbrains.annotations.NotNull;
-
-abstract class TextChunk {
-  @NotNull private final CharSequence myText;
-  private final int myOffset1;
-  private final int myOffset2;
-
-  public TextChunk(@NotNull CharSequence text, int offset1, int offset2) {
-    myText = text;
-    myOffset1 = offset1;
-    myOffset2 = offset2;
-  }
-
-  @Override
-  public abstract int hashCode();
-
-  @Override
-  public abstract boolean equals(Object obj);
-
-  @NotNull
-  public CharSequence getContent() {
-    return myText.subSequence(myOffset1, myOffset2);
-  }
-
-  @NotNull
-  public CharSequence getOriginalText() {
-    return myText;
-  }
-
-  public int getOffset1() {
-    return myOffset1;
-  }
-
-  public int getOffset2() {
-    return myOffset2;
-  }
-
-  @Override
-  public String toString() {
-    return getContent().toString();
-  }
-}
index 10a4fc0de250cca5b5732db295b03e5c1137c271..346e1402e4895ecf164110876a19c0864aa89ab8 100644 (file)
@@ -18,7 +18,6 @@ package com.intellij.diff.comparison.iterables;
 import com.intellij.diff.comparison.DiffTooBigException;
 import com.intellij.diff.comparison.TrimUtil;
 import com.intellij.diff.fragments.DiffFragment;
-import com.intellij.diff.fragments.DiffFragmentImpl;
 import com.intellij.diff.util.Range;
 import com.intellij.openapi.progress.ProgressIndicator;
 import com.intellij.openapi.util.Comparing;
@@ -88,20 +87,6 @@ public class DiffIterableUtil {
     return diff(data1, data2, indicator);
   }
 
-  /*
-   * Compare two arrays, basing on equals() and hashCode() of it's elements
-   *
-   * If the input arrays are too big, "everything is changed" can be returned.
-   */
-  @NotNull
-  public static <T> FairDiffIterable diffSomehow(@NotNull T[] data1, @NotNull T[] data2, @NotNull ProgressIndicator indicator) {
-    indicator.checkCanceled();
-
-    // TODO: use ProgressIndicator inside
-    Diff.Change change = Diff.buildChangesSomehow(data1, data2);
-    return fair(create(change, data1.length, data2.length));
-  }
-
   //
   // Iterable
   //
@@ -158,15 +143,6 @@ public class DiffIterableUtil {
   // Misc
   //
 
-  @NotNull
-  public static List<DiffFragment> convertIntoFragments(@NotNull DiffIterable changes) {
-    final List<DiffFragment> fragments = new ArrayList<>();
-    for (Range ch : changes.iterateChanges()) {
-      fragments.add(new DiffFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2));
-    }
-    return fragments;
-  }
-
   @NotNull
   public static Iterable<Pair<Range, Boolean>> iterateAll(@NotNull final DiffIterable iterable) {
     return () -> new Iterator<Pair<Range, Boolean>>() {
index eea8b6a2d59002785ddf21d09a365ed986564ea9..a9d7b118fc3c005656048b8fe2be051c1c3432c3 100644 (file)
@@ -15,7 +15,6 @@
  */
 package com.intellij.diff.fragments;
 
-import com.intellij.diff.util.MergeRange;
 import com.intellij.diff.util.ThreeSide;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -57,14 +56,6 @@ public class MergeLineFragmentImpl implements MergeLineFragment {
     myInnerFragments = innerFragments;
   }
 
-  public MergeLineFragmentImpl(@NotNull MergeRange range) {
-    this(range, null);
-  }
-
-  public MergeLineFragmentImpl(@NotNull MergeRange range, @Nullable List<MergeWordFragment> innerFragments) {
-    this(range.start1, range.end1, range.start2, range.end2, range.start3, range.end3, innerFragments);
-  }
-
   public MergeLineFragmentImpl(@NotNull MergeLineFragment fragment, @Nullable List<MergeWordFragment> fragments) {
     this(fragment.getStartLine(ThreeSide.LEFT), fragment.getEndLine(ThreeSide.LEFT),
          fragment.getStartLine(ThreeSide.BASE), fragment.getEndLine(ThreeSide.BASE),
index b95a3e316493e2242c232d292352ce2f4a602fa7..b7abb9c333ed1732b44d9f90b7c931929f0eeebf 100644 (file)
@@ -41,10 +41,6 @@ public class MergeWordFragmentImpl implements MergeWordFragment {
     myEndOffset3 = endOffset3;
   }
 
-  public MergeWordFragmentImpl(@NotNull MergeRange range) {
-    this(range.start1, range.end1, range.start2, range.end2, range.start3, range.end3);
-  }
-
   @Override
   public int getStartOffset(@NotNull ThreeSide side) {
     return side.select(myStartOffset1, myStartOffset2, myStartOffset3);
index dd6e166e4a1640f7c37acc71c02b16b0c7b3ac35..e5de1b18f040246b68f2ec03b0149e40dcbfc5ed 100644 (file)
@@ -18,7 +18,7 @@ package com.intellij.diff.merge;
 import com.intellij.diff.DiffContext;
 import com.intellij.diff.FrameDiffTool;
 import com.intellij.diff.actions.ProxyUndoRedoAction;
-import com.intellij.diff.comparison.ByLine;
+import com.intellij.diff.comparison.ComparisonManager;
 import com.intellij.diff.comparison.ComparisonMergeUtil;
 import com.intellij.diff.comparison.ComparisonPolicy;
 import com.intellij.diff.comparison.DiffTooBigException;
@@ -363,8 +363,9 @@ public class TextMergeViewer implements MergeTool.MergeViewer {
           return ContainerUtil.map(documents, Document::getImmutableCharSequence);
         });
 
-        List<MergeLineFragment> lineFragments = ByLine.compareTwoStep(sequences.get(0), sequences.get(1), sequences.get(2),
-                                                                      ComparisonPolicy.DEFAULT, indicator);
+        ComparisonManager manager = ComparisonManager.getInstance();
+        List<MergeLineFragment> lineFragments = manager.compareLines(sequences.get(0), sequences.get(1), sequences.get(2),
+                                                                     ComparisonPolicy.DEFAULT, indicator);
 
         List<MergeConflictType> conflictTypes = ReadAction.compute(() -> {
           indicator.checkCanceled();
index 3d23255501486aa0f46dbb9ab5c8d5d55d302982..c67f66adcf116b8a4b0bf2026ec40d44dc1bfb66 100644 (file)
@@ -16,7 +16,7 @@
 package com.intellij.diff.tools.simple;
 
 import com.intellij.diff.DiffContext;
-import com.intellij.diff.comparison.ByLine;
+import com.intellij.diff.comparison.ComparisonManager;
 import com.intellij.diff.comparison.ComparisonPolicy;
 import com.intellij.diff.comparison.DiffTooBigException;
 import com.intellij.diff.contents.DiffContent;
@@ -125,8 +125,10 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx {
       });
 
       final ComparisonPolicy comparisonPolicy = getIgnorePolicy().getComparisonPolicy();
-      List<MergeLineFragment> lineFragments = ByLine.compareTwoStep(sequences.get(0), sequences.get(1), sequences.get(2),
-                                                                    comparisonPolicy, indicator);
+
+      ComparisonManager manager = ComparisonManager.getInstance();
+      List<MergeLineFragment> lineFragments = manager.compareLines(sequences.get(0), sequences.get(1), sequences.get(2),
+                                                                   comparisonPolicy, indicator);
 
       List<MergeConflictType> conflictTypes = ReadAction.compute(() -> {
         indicator.checkCanceled();
index 36431c682616dbeaabd4c206e760c237feea0791..4de112cd371bdaeb50eeee73dbc44f51e9514ec1 100644 (file)
@@ -134,7 +134,7 @@ class ComparisonUtilAutoTest : DiffTestCase() {
       val sequence2 = text2.charsSequence
       val sequence3 = text3.charsSequence
 
-      val fragments = ByLine.compareTwoStep(sequence1, sequence2, sequence3, policy, INDICATOR)
+      val fragments = MANAGER.compareLines(sequence1, sequence2, sequence3, policy, INDICATOR)
 
       val fineFragments = fragments.map { f ->
         val chunk1 = DiffUtil.getLinesContent(text1, f.startLine1, f.endLine1)
index 9144618851d3aa02c729553e398ed9e22385e6f4..2eab93eccb42e8d7a22b22c6f5bfa160862652df 100644 (file)
@@ -401,6 +401,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
       // TODO ("      _-------_  _ _      " - "      _  _ _      ").trim()
       ("      _-------_  _ _      " - "      _  _ _      ").default()
       ("      _       _--_-_------" - "      _--_-_      ").trim()
+      ("      _-------_  _ _      " - "      _  _ _      ").ignore()
       testAll()
     }
 
@@ -416,7 +417,6 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
     lines() {
       ("====}_==== }_Y_====}" - "====}_Y_====}")
       ("     _------_ _     " - "     _ _     ").default() // result after second step correction
-      ("     _      _-_-----" - "     _-_     ").ignore()  // result looks strange because of 'diff.unimportant.line.char.count'
       testAll()
     }
   }
@@ -428,4 +428,59 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
       testDefault()
     }
   }
+
+  fun `test ignore whitespace policy applies two-step correction`() {
+    lines() {
+      ("1_ _  1" - "  1")
+      ("-_-_   " - "   ").default()
+      (" _-_---" - "   ").trim()
+      ("-_-_   " - "   ").ignore()
+      testAll()
+    }
+
+    lines() {
+      ("  1_ _1" - "  1")
+      ("   _-_-" - "   ").default()
+      testAll()
+    }
+
+    lines() {
+      ("X_ Y_X" - "Y ")
+      ("-_--_-" - "--").default()
+      ("-_  _-" - "  ").trim()
+      testAll()
+    }
+  }
+
+  fun `test regression - second step correction should be performed if there are no ambigous matchings`() {
+    lines {
+      ("}_ }" - " }_}")
+      ("-_--" - "--_-").default()
+      (" _  " - "  _ ").trim()
+      testAll()
+    }
+
+    lines {
+      (" }_}_ }" - "}_}_}")
+      ("--_ _--" - "-_ _-").default()
+      ("  _ _  " - " _ _ ").trim()
+      testAll()
+    }
+
+    lines() {
+      ("X_X __Y" - "X__Z")
+      (" _--__-" - " __-").default()
+      ("-_  __-" - " __-").trim()
+      testAll()
+    }
+  }
+
+  fun `test regression - second step with too many possible matchings`() {
+    lines {
+      (" X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_ X" - "X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X ")
+      ("--_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _-_-_-_-_-_--" - "-_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _--").default()
+      ("  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _-_-_-_-_--" - " _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  ").trim()
+      testAll()
+    }
+  }
 }
index 5af892c1ec5fe5a7f6281c76866e4eb678f29bd1..78b2f6c13262fa329fa861923fbd700931315a40 100644 (file)
Binary files a/platform/icons/src/icon.png and b/platform/icons/src/icon.png differ
diff --git a/platform/icons/src/windows/close.png b/platform/icons/src/windows/close.png
deleted file mode 100644 (file)
index 4c593ad..0000000
Binary files a/platform/icons/src/windows/close.png and /dev/null differ
diff --git a/platform/icons/src/windows/closeActive.png b/platform/icons/src/windows/closeActive.png
new file mode 100644 (file)
index 0000000..9399d0a
Binary files /dev/null and b/platform/icons/src/windows/closeActive.png differ
diff --git a/platform/icons/src/windows/closeActive@2x.png b/platform/icons/src/windows/closeActive@2x.png
new file mode 100644 (file)
index 0000000..0d27cde
Binary files /dev/null and b/platform/icons/src/windows/closeActive@2x.png differ
diff --git a/platform/icons/src/windows/closeActive@2x_dark.png b/platform/icons/src/windows/closeActive@2x_dark.png
new file mode 100644 (file)
index 0000000..bfad5bb
Binary files /dev/null and b/platform/icons/src/windows/closeActive@2x_dark.png differ
diff --git a/platform/icons/src/windows/closeActive_dark.png b/platform/icons/src/windows/closeActive_dark.png
new file mode 100644 (file)
index 0000000..c7b47d6
Binary files /dev/null and b/platform/icons/src/windows/closeActive_dark.png differ
diff --git a/platform/icons/src/windows/closeHover.png b/platform/icons/src/windows/closeHover.png
new file mode 100644 (file)
index 0000000..6b00951
Binary files /dev/null and b/platform/icons/src/windows/closeHover.png differ
diff --git a/platform/icons/src/windows/closeHover@2x.png b/platform/icons/src/windows/closeHover@2x.png
new file mode 100644 (file)
index 0000000..33cb80c
Binary files /dev/null and b/platform/icons/src/windows/closeHover@2x.png differ
diff --git a/platform/icons/src/windows/closeInactive.png b/platform/icons/src/windows/closeInactive.png
new file mode 100644 (file)
index 0000000..a249384
Binary files /dev/null and b/platform/icons/src/windows/closeInactive.png differ
diff --git a/platform/icons/src/windows/closeInactive@2x.png b/platform/icons/src/windows/closeInactive@2x.png
new file mode 100644 (file)
index 0000000..4d23243
Binary files /dev/null and b/platform/icons/src/windows/closeInactive@2x.png differ
diff --git a/platform/icons/src/windows/closeInactive@2x_dark.png b/platform/icons/src/windows/closeInactive@2x_dark.png
new file mode 100644 (file)
index 0000000..e5d8f66
Binary files /dev/null and b/platform/icons/src/windows/closeInactive@2x_dark.png differ
diff --git a/platform/icons/src/windows/closeInactive_dark.png b/platform/icons/src/windows/closeInactive_dark.png
new file mode 100644 (file)
index 0000000..0be3f45
Binary files /dev/null and b/platform/icons/src/windows/closeInactive_dark.png differ
diff --git a/platform/icons/src/windows/iconify.png b/platform/icons/src/windows/iconify.png
deleted file mode 100644 (file)
index b2dd745..0000000
Binary files a/platform/icons/src/windows/iconify.png and /dev/null differ
diff --git a/platform/icons/src/windows/maximize.png b/platform/icons/src/windows/maximize.png
deleted file mode 100644 (file)
index 4dfcc65..0000000
Binary files a/platform/icons/src/windows/maximize.png and /dev/null differ
diff --git a/platform/icons/src/windows/maximize@2x.png b/platform/icons/src/windows/maximize@2x.png
new file mode 100644 (file)
index 0000000..a9dc5c1
Binary files /dev/null and b/platform/icons/src/windows/maximize@2x.png differ
diff --git a/platform/icons/src/windows/maximize@2x_dark.png b/platform/icons/src/windows/maximize@2x_dark.png
new file mode 100644 (file)
index 0000000..c12370c
Binary files /dev/null and b/platform/icons/src/windows/maximize@2x_dark.png differ
diff --git a/platform/icons/src/windows/maximizeInactive.png b/platform/icons/src/windows/maximizeInactive.png
new file mode 100644 (file)
index 0000000..688e4e3
Binary files /dev/null and b/platform/icons/src/windows/maximizeInactive.png differ
diff --git a/platform/icons/src/windows/maximizeInactive@2x.png b/platform/icons/src/windows/maximizeInactive@2x.png
new file mode 100644 (file)
index 0000000..1b8ba51
Binary files /dev/null and b/platform/icons/src/windows/maximizeInactive@2x.png differ
diff --git a/platform/icons/src/windows/maximizeInactive@2x_dark.png b/platform/icons/src/windows/maximizeInactive@2x_dark.png
new file mode 100644 (file)
index 0000000..a335b14
Binary files /dev/null and b/platform/icons/src/windows/maximizeInactive@2x_dark.png differ
diff --git a/platform/icons/src/windows/maximizeInactive_dark.png b/platform/icons/src/windows/maximizeInactive_dark.png
new file mode 100644 (file)
index 0000000..23d7af2
Binary files /dev/null and b/platform/icons/src/windows/maximizeInactive_dark.png differ
diff --git a/platform/icons/src/windows/maximize_dark.png b/platform/icons/src/windows/maximize_dark.png
new file mode 100644 (file)
index 0000000..ff9b206
Binary files /dev/null and b/platform/icons/src/windows/maximize_dark.png differ
index dc6b39109161e89489e7ab0f1493084f5d20cd04..f21aafd5314b95ee7cc11fda2e60c300de7339b4 100644 (file)
Binary files a/platform/icons/src/windows/minimize.png and b/platform/icons/src/windows/minimize.png differ
diff --git a/platform/icons/src/windows/minimize@2x.png b/platform/icons/src/windows/minimize@2x.png
new file mode 100644 (file)
index 0000000..fa32e78
Binary files /dev/null and b/platform/icons/src/windows/minimize@2x.png differ
diff --git a/platform/icons/src/windows/minimize@2x_dark.png b/platform/icons/src/windows/minimize@2x_dark.png
new file mode 100644 (file)
index 0000000..f463d2d
Binary files /dev/null and b/platform/icons/src/windows/minimize@2x_dark.png differ
diff --git a/platform/icons/src/windows/minimizeInactive.png b/platform/icons/src/windows/minimizeInactive.png
new file mode 100644 (file)
index 0000000..49be621
Binary files /dev/null and b/platform/icons/src/windows/minimizeInactive.png differ
diff --git a/platform/icons/src/windows/minimizeInactive@2x.png b/platform/icons/src/windows/minimizeInactive@2x.png
new file mode 100644 (file)
index 0000000..afe98f8
Binary files /dev/null and b/platform/icons/src/windows/minimizeInactive@2x.png differ
diff --git a/platform/icons/src/windows/minimizeInactive@2x_dark.png b/platform/icons/src/windows/minimizeInactive@2x_dark.png
new file mode 100644 (file)
index 0000000..a4fd6ce
Binary files /dev/null and b/platform/icons/src/windows/minimizeInactive@2x_dark.png differ
diff --git a/platform/icons/src/windows/minimizeInactive_dark.png b/platform/icons/src/windows/minimizeInactive_dark.png
new file mode 100644 (file)
index 0000000..c5ff313
Binary files /dev/null and b/platform/icons/src/windows/minimizeInactive_dark.png differ
diff --git a/platform/icons/src/windows/minimize_dark.png b/platform/icons/src/windows/minimize_dark.png
new file mode 100644 (file)
index 0000000..01275e1
Binary files /dev/null and b/platform/icons/src/windows/minimize_dark.png differ
diff --git a/platform/icons/src/windows/restore.png b/platform/icons/src/windows/restore.png
new file mode 100644 (file)
index 0000000..9dcafef
Binary files /dev/null and b/platform/icons/src/windows/restore.png differ
diff --git a/platform/icons/src/windows/restore@2x.png b/platform/icons/src/windows/restore@2x.png
new file mode 100644 (file)
index 0000000..2d1fc2b
Binary files /dev/null and b/platform/icons/src/windows/restore@2x.png differ
diff --git a/platform/icons/src/windows/restore@2x_dark.png b/platform/icons/src/windows/restore@2x_dark.png
new file mode 100644 (file)
index 0000000..0fa65cd
Binary files /dev/null and b/platform/icons/src/windows/restore@2x_dark.png differ
diff --git a/platform/icons/src/windows/restoreInactive.png b/platform/icons/src/windows/restoreInactive.png
new file mode 100644 (file)
index 0000000..6e25f28
Binary files /dev/null and b/platform/icons/src/windows/restoreInactive.png differ
diff --git a/platform/icons/src/windows/restoreInactive@2x.png b/platform/icons/src/windows/restoreInactive@2x.png
new file mode 100644 (file)
index 0000000..2faaa2b
Binary files /dev/null and b/platform/icons/src/windows/restoreInactive@2x.png differ
diff --git a/platform/icons/src/windows/restoreInactive@2x_dark.png b/platform/icons/src/windows/restoreInactive@2x_dark.png
new file mode 100644 (file)
index 0000000..056a3a5
Binary files /dev/null and b/platform/icons/src/windows/restoreInactive@2x_dark.png differ
diff --git a/platform/icons/src/windows/restoreInactive_dark.png b/platform/icons/src/windows/restoreInactive_dark.png
new file mode 100644 (file)
index 0000000..718897b
Binary files /dev/null and b/platform/icons/src/windows/restoreInactive_dark.png differ
diff --git a/platform/icons/src/windows/restore_dark.png b/platform/icons/src/windows/restore_dark.png
new file mode 100644 (file)
index 0000000..ae6ffc8
Binary files /dev/null and b/platform/icons/src/windows/restore_dark.png differ